继续整理记录这段时间来的收获,详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用!
5.3 适配器模式
5.3.1 概述
- 将一个类的接口转换为客户希望的另一种接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作
- 分为类适配器模式和对象适配器模式,前者类之间耦合度高于后者且要求程序员了解现有组件库中的相关紫剑的内部结构,故应用少
5.3.2 结构
- 目标(Target)接口:当前系统业务所期待几口,可以为抽象类或接口
- 适配者(Adaptee)类:是 被访问和适配的现存组件库中的组件接口
- 适配器(Adapter)类:转换器,通过继承或引用适配者对象,将适配者接口转换为目标接口,让客户按目标接口的格式访问适配者
5.3.3 类适配器模式
读卡器案例,代码如下:
//适配者类接口
public interface TFcards {
// 从TF卡读取数据
String readTF();
// 往TF可写数据
void writeTF(String message);
}
//适配者类
public class TFCardsImpl implements TFcards{
@Override
public String readTF() {
String message = "TFCards read message: Hello World!";
return message;
}
@Override
public void writeTF(String message) {
System.out.println("TFCards write message:" + message);
}
}
//目标类接口
public interface SDCards {
// 从SD卡读取数据
String readSD();
// 往SD可写数据
void writeSD(String message);
}
//目标类接口
public class SDCardsImpl implements SDCards{
@Override
public String readSD() {
String message = "SDCards read message: Hello World! SD!";
return message;
}
@Override
public void writeSD(String message) {
System.out.println("SDCards write message:" + message);
}
}
//电脑使用类
public class Computer {
public String readSD(SDCards sdCards)
{
if(sdCards == null)
throw new NullPointerException("SD card is not null");
return sdCards.readSD();
}
}
//适配器类
public class SDAdaptorTF extends TFCardsImpl implements SDCards{
@Override
public String readSD() {
System.out.println("adaptor read tf card:");
return readTF();
}
@Override
public void writeSD(String message) {
System.out.println("adaptor write tf card:");
writeTF(message);
}
//测试类
public static void main(String[] args) {
//创建计算机对象
Computer computer = new Computer();
// 读取SD卡数据
String s = computer.readSD(new SDCardsImpl());
System.out.println(s);
System.out.println("========================");
// 使用该电脑读取TF卡数据
// 定义适配器类对象
SDAdaptorTF sdAdaptorTF =new SDAdaptorTF();
String s1 = computer.readSD(sdAdaptorTF);
System.out.println(s1);
}
- 结果如图
- 类图
注:
类适配器模式违背了合成复用原则,仅在客户类有一个接口规范的情况下可用
5.2.4 对象适配器模式
- 与类适配器模式案例一样,代码差不多,不同点
//适配器类
public class SDAdaptorTF implements SDCards {
// 声明适配者类
private TFcards tFcards;
public SDAdaptorTF(TFcards tFcards)
{
this.tFcards = tFcards;
}
@Override
public String readSD() {
System.out.println("adaptor read tf card:");
return tFcards.readTF();
}
@Override
public void writeSD(String message) {
System.out.println("adaptor write tf card:");
tFcards.writeTF(message);
}
}
//测试
public static void main(String[] args) {
//创建计算机对象
Computer computer = new Computer();
// 读取SD卡数据
String s = computer.readSD(new SDCardsImpl());
System.out.println(s);
System.out.println("========================");
// 使用该电脑读取TF卡数据
// 定义适配器类对象
SDAdaptorTF sdAdaptorTF =new SDAdaptorTF(new TFCardsImpl());
String s1 = computer.readSD(sdAdaptorTF);
System.out.println(s1);
}
- 结果
- 类图
- 注意
还有一接口适配器模式,当不希望实现一个接口中所有方法时可以创建一个抽象类Adaptor,实现所有方法,此时只需要继承该抽象类即可
5.2.5 应用场景
- 旧开发系统存在满足新系统功能需求类,但接口同新系统接口不一样
- 使用第三方提供组件,但组件定义和自己要求接口定义不一样
5.2.6 JDK源码案例
Reader(字符流)、InputStream(字节流)的适配使用就是InputStreanReader
InputStremReader继承java.io包中的Reader,对其中抽象未实现方法给出实现,如下:
public int read() throws IOException {
return sd.read();
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
代码中的sd(StreamDecoder类对象),在Sun的JDK实现汇总,实际方法是对sun.nio.cs.StreamDecoder类同名方法的调用封装,类图如下:
上图可以看出:
- InputStreamReader是对同样实现了Reader的StreamDecoder的封装
- StreamDecoder不是Java SE API的内容,是Sun JDK的自身实现,是对构造方法中的字节流类(InputStream)进封账,并通过该类进行字节流和字符流之间解码转换
结论:
表层看,InputStreamReader做了InputStream字节流类到Reader字符流之间转换,从上图看,StreamDecoder的设计实际采用了适配器模式