适配器模式
适配器模式是一种结构型设计模式。用于将两个互不相关的类进行连接
首先我们来描述一个场景:QQ用来发送qq消息,微信用来发送微信消息
public interface QQ {
void sendQQMsg();
}
public class QQImpl implements QQ {
@Override
public void sendQQMsg() {
System.out.println("send by QQ");
}
}
public interface Weixin {
void sendWeixinMsg();
}
public class WeixinImpl implements Weixin {
@Override
public void sendWeixinMsg() {
System.out.println("send by weixin");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这时对场景进行更改,我们想要QQ也可以发送微信消息。最简单的修改就是再QQImpl中加一个发送微信的方法,代码如下
public class QQImpl implements QQ {
@Override
public void sendQQMsg() {
System.out.println("send by QQ");
}
public void sendWeixinMsg() {
sendQQMsg();
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
这么改有什么隐患呢?
- 首先,这么修改违反了开闭原则,对QQImpl类产生的修改
- QQImpl承担了不属于它的职责,违法了单一职责原则
那么我们换一种修改方法,单独增加一个类来完成上述需求,那么这个类就要满足两个条件:
- 这个新的类也是QQ类,因为需求要求的使qq也可以发送微信
- 这个类的职责是使用qq发送微信消息
于是乎原代码不变,新增QQAdapter,代码如下
public class QQAdapter implements Weixin {
private QQ qq;
public QQAdapter(QQ qq) {
this.qq = qq;
}
@Override
public void sendWeixinMsg() {
qq.sendQQMsg();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
总结
在上述代码中,QQAdapter被称为Adapter(适配器),QQ被称为Adaptee(适配者),Weixin被称为Target(目标物),其类图如下
使用适配器模式,最明显的两个优点就是保持了开闭原则和事Adaptee和目标类解耦
源码展示
在jdk源码中,同样用到了适配器模式,我们在使用FutureTask时,既可以使用Callable接口类作为参数,也可以使用Runnable接口类作为参数,这其中也是使用了适配器的方式,源码如下
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
RunnableAdapter源码如下
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
其中Runnable和result作为Adaptee,Callable作为Target