什么是适配器模式?
– 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
生活中的场景
模式中的角色
– 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
– 需要适配的类(Adaptee):需要适配的类或适配者类。
– 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。
可以解决下面因为接口不兼容为引起的问题
使用适配器之后:
所以我们可以知道适配器模式:
1.创建一个适配器的类
2.适配器的类中需要有被适配器对象的引用,即哪个类需要被适配。
3.适配器需要实现一个接口,这个接口是我们想要的类型的接口,
具体的代码实现:
目标接口:
public interface Target {
void handle();
}
/*
* 被适配的类
* (相当于例子中的,PS/2键盘)
* */
public class Adaptee {
public void request(){
System.out.println("可以完成客户请求的需要的功能!");
}
}
适配器类的的定义:
/*
* 适配器(类适配器方式)
* (相当于usb和ps/2的转接器)
* */
public class Adapter implements Target{
private Adaptee adaptee;//被适配器对象的引用
public Adapter(Adaptee adaptee) {//传入需要适配的对象
this.adaptee = adaptee;
}
@Override
public void handle() { //其实也是调用被适配器的方法
adaptee.request();
}
}
模拟使用:
/*
* 客户端
* (相当于例子中的笔记本,只有USB接口)
* 需求:有一个笔记本和键盘,但是笔记本的usb接口和键盘的接口不匹配
* 这时就需要一个转接口,进行适配
* */
public class Client {
public static void main(String[] args) {
Client c=new Client();
Adaptee adaptee=new Adaptee();
Target t=new Adapter(adaptee);
c.test1(t);
}
public void test1(Target t){
t.handle();
}
}
接下来,让我们分析一下FutureTask的源码说一下适配器模式,关于FutureTask是关于多线程并发方面的知识,这里不是我们的重点,不知道也不影响对适配器模式的理解。
public class FutureTask<V> implements RunnableFuture<V> {
private volatile int state;
private Callable<V> callable; //在FutureTask中有一个Callable的成员变量
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
}
这里我仅贴出部分源码,在FutureTask类中,有一个Callable的成员变量成员变量,但现在我们有一个需求,让这个成员变量不仅能够接受Callable类型的对象,还能接受Runnable类型的对象,这就需要用到适配器模式了。
我们知道Callable和Runnable是两个不同类型的接口,他们的子类也不相同,贴出源码:
Runnable接口:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Callable接口:
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
再看上面的FutureTask的两个构造器,一个传入的是Callable类型的对象,一个是Runnable类型的对象,我们的目的是把Runnable类型的对象转化为Callable类型的对象,上面有这一句this.callable = Executors.callable(runnable, result);我们跟进去看一下 Executors.callable(runnable, result)的方法。
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result); //适配器
}
这时可以看到返回的是RunnableAdapter类型,它将Runnable转化为Callable,我们再次跟进RunnableAdapter<T>(task, result)看一看
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.构造器传入这个需要被适配的对象,然后调用Callable方法,在里面调用Runnable接口的方法。