一、概述
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁,它结合了两个独立接口的功能,
使得原本由于接口不兼容而不能一起工作的那些类可以一起工作,属于结构型模式。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。
eg: 读卡器是作为内存卡和笔记本之间的适配器,
内存卡 => 读卡器 => 笔记本
将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
分类:
类适配器、对象适配器、接口适配器。
角色模型:
目标接口(Target):该角色把其他类转换为我们期望的接口
被适配者/源接口(Adaptee): 原有的接口,也是希望被改变的接口
适配器(Adapter): 将被适配者和目标接口组合到一起的类
如上示例:选取笔记本为主体,笔记本需要读取内存卡,则笔记本为目标接口,内存卡为被适配者,读卡器为适配器。
适配器模式结构图:
二、使用
1. 笔记本案例
现有一个apple笔记本(USB接口),和一个内存卡(SM接口),如何实现apple读取内存卡数据?
/** * 目标 Target */ class Apple { public void usb() { System.out.println("数据从usb接口输入"); } } /** * 源 Adaptee */ interface Sm { void smType(); } /** * 测试类*/ public class AdapterTest { public static void main(String[] args) { // 原始的apple读取usb接口数据 Apple apple = new Apple(); AdapterTest.client(apple); } /** * 客户端 */ public static void client(Apple apple) { System.out.println("========苹果笔记本读取数据======="); apple.usb(); } }
当然,如上的源
1.1 类适配器
原理:通过继承特性来实现
/** * 1.类适配器 Adapter */ class ReaderCard extends Apple implements Sm { @Override public void smType() { System.out.println("数据从SM接口输出"); } @Override public void usb() { this.smType(); super.usb(); } } public class AdapterTest { public static void main(String[] args) { // 1.采用类适配器后,读取sm接口数据 ReaderCard readerCard = new ReaderCard(); AdapterTest.client(readerCard); } }
总结:类适配器通过创建一个适配器类,使这个适配器继承Target和Adaptee接口,来将原来并不兼容的目标接口和源接口关联在了一起,这样使得适配器同时具有了两个接口的功能。客户端使用时,原来是要求传入一个Apple接口(后代),现在适配器也是Apple的后代,可以直接传递(面向接口编程)。
1.2 对象适配器
原理:通过组合方式 + 构造注入的方式实现
/** * 2.对象适配器 */ class ReaderCard2 extends Apple { // 组合 private Sm sm; // 构造注入 public ReaderCard2(Sm sm) { this.sm = sm; } @Override public void usb() { sm.smType(); super.usb(); } } public class AdapterTest { public static void main(String[] args) { // 2.对象适配器 ReaderCard2 readerCard2 = new ReaderCard2(() -> System.out.println("数据从SM接口输出")); AdapterTest.client(readerCard2); } }
总结:对象适配器通过创建一个适配器类,实现Target接口,然后使用构造注入的方式注入Adaptee,这样适配器类就组合了两个不兼容的接口,客户端要求使用Target接口,适配器又是Target的后代,这样就可以直接传递,同时,通过注入将源关联起来。
1.3 类适配器
原理:可以认为是和类适配器是同一种。
2. 案例二
都知道创建现在的第三种方式是通过实现Callable接口,那么它是如何和Thread关联上的?
public class CallableDemo { public static void main(String[] args) throws Exception { // 两个线程,一个main线程,一个AAA futureTask // FutureTask(Callable<V> callable) FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread());new Thread(futureTask, "AAA").start(); } } class MyThread implements Callable<Integer> { @Override public Integer call() throws Exception {return 1024; } } class MyThread1 implements Runnable{ @Override public void run() { } }
创建线程需要传入一个Runnable接口,并没有构造方法让你去传Callable接口,而你有的只是一个Callable结构的实例,那你咋办?你如何将Callable传递给Thread呢?
分析:接口支持多次实现,如果能找到一个类,这个类实现了Runnable接口,又实现了Callable接口,那么传递一个这样的类,即可解决问题,这就是适配器模式。
(1) 创建线程需要传递Runnable接口,即只需要是Runnable的 后代接口、后台接口的实现类都可以传递,RunnableFuture接口实现了Runnable接口,类FutureTask又实现了RunnableFuture接口,所以可以传递FutureTask类;
(2) FutureTask类的构造注入可以传递进去一个Callable接口,所以FutureTask可以整合Runnable和Callable接口;
参考: