定义与特点
在现实生活中,经常出现两个对象因接口不兼容而不能在一起工作的例子,这时需要第三者进行适配。例如,讲中文的人同讲英文的人对话时需要一个翻译,用直流电的笔记本电脑接交流电源时需要一个电源适配器,用计算机访问照相机的 SD 内存卡时需要一个读卡器等。
- 定义
将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配。
参与角色
- Target(目标接口):当前系统业务所期待的适配器接口类,它可以是抽象类或接口。
- Adaptee(适配者类):被适配的角色,是一个已经存在的接口,这个接口需要我们适配才能使用,适配者类提供了客户希望使用但无法直接使用的业务方法。
- Adapter(适配器类):实现Target,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。
结构类图
适配器模式分为 类适配器模式 和 对象适配器模式。
类适配器:采用继承的方式,静态的定义,耦合度比较高,较少使用。
对象适配器:采用对象聚合的方式,耦合度低,常用。
- 类适配器模式
- 对象适配器模式
模式代码示例
类适配器模式的代码如下
package com.it235.adapter.clazz; //目标接口,客户端所期待调用的方法 interface Target{ public void request(); } //适配者接口,客户端想调用但是又无法调用的方法 class Adaptee{ public void specificRequest(){ System.out.println("适配者中的业务代码被调用!"); } } //类适配器类 class ClassAdapter extends Adaptee implements Target{ public void request(){ specificRequest(); } } //客户端代码 public class ClassAdapterTest{ public static void main(String[] args){ System.out.println("类适配器模式测试:"); Target target = new ClassAdapter(); target.request(); } } //运行结果 类适配器模式测试: 适配者中的业务代码被调用!
对象适配器模式的代码如下
package com.it235.adapter.object; //目标接口 interface Target{ public void request(); } //适配者接口 class Adaptee{ public void specificRequest(){ System.out.println("适配者中的业务代码被调用!"); } } //对象适配器类 class ObjectAdapter implements Target{ private Adaptee adaptee; public ObjectAdapter(Adaptee adaptee){ this.adaptee = adaptee; } public void request(){ adaptee.specificRequest(); } } //客户端代码 public class ObjectAdapterTest{ public static void main(String[] args){ System.out.println("对象适配器模式测试:"); Adaptee adaptee = new Adaptee(); Target target = new ObjectAdapter(adaptee); target.request(); } } //运行结果 对象适配器模式测试: 适配者中的业务代码被调用!
模式实现分析
电脑通过读卡器读取TF存储卡,在智能机刚出现的时候,手机中的内存卡是可卸载的,如果要下载歌曲或者电影,我们需要拔出该存储卡之后,通过读卡器去电脑上下载,现在我们模拟电脑读取SD卡和TF内存卡之间的适配关系。
需求:电脑可以直接读取SD卡(大型一点的卡),SD卡可以充当读卡器的作用读取小的TF卡。
计算机读取SD卡程序
interface SDCard { //读取SD卡方法 String readSD(); //写入SD卡功能 int writeSD(String msg); } //华为生产的SD卡 class HuaWeiSDCard implements SDCard { @Override public String readSD() { return "读SD卡"; } @Override public int writeSD(String msg) { System.out.println("写SD卡"); return 1; } } //计算机 class Computer { public String readSD(SDCard sdCard) { return sdCard.readSD(); } } //客户进行插卡操作 public class SDCardTest { public static void main(String[] args) { Computer computer = new Computer(); SDCard sdCard = new HuaWeiSDCard(); System.out.println(computer.readSD(sdCard)); } }
一般笔记本电脑都支持直接读取SD卡,但不支持读取手机中的TF小卡,这里我们让SD卡充当读卡器的作用,将TF小卡放置到SD卡上就可以完成电脑对TF小卡的读取。这里的适配器就是SD卡。
创建TF卡对象
//TF卡接口 interface TFCard { String readTF(); int writeTF(String msg); } //华为TF卡 class HuaWeiTFCard implements TFCard { @Override public String readTF() { return "读TF卡"; } @Override public int writeTF(String msg) { System.out.println("写TF卡"); return 1; } }
此时TF卡我们拿到了,但是
Computer
类目前只支持读SD卡,Computer
已经出厂了,无法再进行卡槽扩充更改,所以我们要赋予SD卡适配器的功能,让给SD卡适配TF卡。加入适配器,将SD支持TF卡操作
类适配模式
创建适配器类,继承了被适配类,同时实现标准接口
//类适配模式 class SDAdapterTF extends HuaWeiTFCard implements SDCard { @Override public String readSD() { System.out.println("适配读取TF卡,充当转接作用"); return super.readTF(); } @Override public int writeSD(String msg) { System.out.println("适配写入TF卡,充当转接作用"); return super.writeTF(msg); } } //客户端调用 public class ClassAdapterTest { public static void main(String[] args) { Computer computer = new Computer(); SDCard tfCardAdapterSD = new SDAdapterTF(); System.out.println(computer.readSD(tfCardAdapterSD)); } }
该模式基于继承实现,不利于扩展,使用比较少
对象适配模式
创建适配器类,实现标准接口,将这个调用委托给实现新接口的对象来处理
//对象适配模式 class SDAdapterTF implements SDCard { private TFCard tfCard; public SDAdapterTF(TFCard tfCard) { this.tfCard = tfCard; } @Override public String readSD() { System.out.println("适配读取TF卡,充当转接作用"); return tfCard.readTF(); } @Override public int writeSD(String msg) { System.out.println("适配写入TF卡,充当转接作用"); return tfCard.writeTF(msg); } } //客户端调用 public class ClassAdapterTest { public static void main(String[] args) { Computer computer = new Computer(); TFCard tfCard = new HuaWeiTFCard(); SDCard tfCardAdapterSD = new SDAdapterTF(tfCard); System.out.println(computer.readSD(tfCardAdapterSD)); } }
对象适配模式基于组合实现,依赖较弱,扩展性强
JDK中的案例
java.util.Arrays#asList()
java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)
下面以InputStreamReader
和OutputStreamWriter
类为例介绍适配器模式。 InputStreamReader
和OutputStreamWriter
分别继承Reader
和Writer
两个抽象类,但是要创建它们的对象必须在构造函数中传入一个InputStream
和OutputStream
的实例。
InputStreamReader
和OutputStreamWriter
也就是将InputStream
和OutputStream
适配到Reader
和Writer
。
总结
优点如下。
- 客户端通过适配器可以透明地调用目标接口。
- 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
其缺点是:对类适配器来说,更换适配器的实现过程比较复杂,过多使用会导致系统凌乱,追溯困难(内部转发导致,调用A适配成B)。
适用场景
- 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
- 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。