1. 适配器模式
注意:代理模式侧重访问控制功能(中介)。适配器模式侧重将适配者类转换成目标接口
生活中经常出现两个对象因接口不兼容而不能一起工作的实例,这时需要第三者进行适配转换。例如讲中文的人同讲英文的人对话时需要一个翻译,用直流电的笔记本电脑接交流电源时需要一个电源适配器
软件设计中也会出现当前系统与某个依赖组件之间接口不兼容,这时用适配器模式能很好地解决这些问题
1.1 定义、优缺点、适用场景
定义:适配器将一个类接口转换成另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,所以应用相对较少些
优点:
- 客户端通过适配器可以透明地调用目标接口
- 可以直接复用现有的适配者类
- 将目标接口和适配者类解耦,解决了目标接口和适配者类接口不一致的问题
- 在很多业务场景中符合开闭原则
缺点:
- 适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性
- 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱
适用场景:
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同
1.2 模式的结构与实现(类结构型模式)
结构:
- 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口
- 适配者(Adaptee)类:它是已经存在且提供功能的类,但由于接口不兼容,不能被客户端使用
- 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,这样客户就可以按目标接口的格式访问适配器
实现:
描述:小明是中国人,只能听懂中国人说的话。有一天来了个只会说英语的英国朋友。所以找来了个翻译,翻译将英语翻译成中文,所以小明能听懂翻译这个中国人说的话
public class AdapterTest {
public static void main(String[] args) {
// 翻译为了和小明说话,变成了中国人
Chinese chinese = new Translater();
XiaoMing xiaoMing = new XiaoMing();
xiaoMing.hear(chinese);
}
}
// 目标接口:中国人
interface Chinese {
// 说中文
String speakChinese();
}
class XiaoMing {
// 小明只能听中国人讲话
public void hear(Chinese chinese) {
String chineseWords = chinese.speakChinese();
System.out.println("小明听懂了中国人说的:" + chineseWords);
}
}
// 适配者类:真实的英国人
class RealBritish {
// 说了一句英语
public String speakEnglish() {
System.out.println("英国人说了句: hello");
return "hello";
}
}
// 适配器类:翻译---对接英国人,进行英语翻译。然后翻译为了和小明说话,变成了中国人
class Translater extends RealBritish implements Chinese {
// 翻译说中文
@Override
public String speakChinese() {
String englishWords = speakEnglish();
// 听英国人说的英语,然后转换成中文,再说出去
System.out.println("翻译将英国人说的:hello,转换成中文:你好");
return "你好";
}
}
运行程序,结果如下:
英国人说了句: hello
翻译将英国人说的:hello,转换成中文:你好
小明懂了中国人讲的:你好
1.3 对象结构型模式
修改适配器类和客户端的代码即可,如下所示:
public class AdapterTest {
public static void main(String[] args) {
// 翻译对接英国人。翻译为了和小明说话,变成了中国人
Chinese chinese = new Translater(new RealBritish());
XiaoMing xiaoMing = new XiaoMing();
xiaoMing.hear(chinese);
}
}
// 目标接口:中国人
interface Chinese {
// 说中文
String speakChinese();
}
class XiaoMing {
// 小明只能听中国人讲话
public void hear(Chinese chinese) {
String chineseWords = chinese.speakChinese();
System.out.println("小明听懂了中国人说的:" + chineseWords);
}
}
// 适配者类:真实的英国人
class RealBritish {
// 说了一句英语
public String speakEnglish() {
System.out.println("英国人说了句: hello");
return "hello";
}
}
// 适配器类:翻译---翻译为了和小明说话,变成了中国人
class Translater implements Chinese {
private RealBritish realBritish;
// 对接英国人,进行英语翻译
public Translater(RealBritish realBritish) {
this.realBritish = realBritish;
}
// 翻译说中文
@Override
public String speakChinese() {
String englishWords = this.realBritish.speakEnglish();
// 听英国人说的英语,然后转换成中文,再说出去
System.out.println("翻译将英国人说的:hello,转换成中文:你好");
return "你好";
}
}
运行程序,结构如下:
英国人说了句: hello
翻译将英国人说的:hello,转换成中文:你好
小明听懂了中国人说的:你好
1.4 双向适配器模式
双向适配器类要么把适配者接口转换成目标接口,要么把目标接口转换成适配者接口。不能同时对适配者接口和目标接口相互转换
public class AdapterTest {
public static void main(String[] args) {
British british = new Translater(new RealChinese());
Tom tom = new Tom();
tom.hear(british);
System.out.println("====昨天的一个翻译将中文翻译成英文。今天的另一个翻译将英文翻译成中文======");
Chinese chinese = new Translater(new RealBritish());
XiaoMing xiaoMing = new XiaoMing();
xiaoMing.hear(chinese);
}
}
// 英文翻译成中文的目标对象
interface Chinese {
String speakChinese();
}
// 中文翻译成英文的适配者类
class RealChinese implements Chinese {
@Override
public String speakChinese() {
System.out.println("中国人说了句: 你好");
return "你好";
}
}
class XiaoMing {
public void hear(Chinese chinese) {
String chineseWords = chinese.speakChinese();
System.out.println("小明听懂了中国人说的:" + chineseWords);
}
}
// 中文翻译成英文的目标对象
interface British {
String speakEnglish();
}
// 英文翻译成中文的适配者类
class RealBritish implements British {
@Override
public String speakEnglish() {
System.out.println("英国人说了句: hello");
return "hello";
}
}
class Tom {
public void hear(British british) {
String englishWords = british.speakEnglish();
System.out.println("Tom听懂了英国人说的:" + englishWords);
}
}
// 要么将中文翻译成英文;要么将英文翻译成中文。不能同时翻译中文和英文
class Translater implements Chinese, British {
private RealChinese realChinese;
private RealBritish realBritish;
public Translater(RealChinese realChinese) {
this.realChinese = realChinese;
}
public Translater(RealBritish realBritish) {
this.realBritish = realBritish;
}
@Override
public String speakEnglish() {
String chineseWords = this.realChinese.speakChinese();
System.out.println("翻译将中国人说的:你好,转换成中文:hello");
return "hello";
}
@Override
public String speakChinese() {
String englishWords = this.realBritish.speakEnglish();
System.out.println("翻译将英国人说的:hello,转换成中文:你好");
return "你好";
}
}
运行程序,结果如下:
中国人说了句: 你好
翻译将中国人说的:你好,转换成中文:hello
Tom听懂了英国人说的:hello
====昨天的一个翻译将中文翻译成英文。今天的另一个翻译将英文翻译成中文======
英国人说了句: hello
翻译将英国人说的:hello,转换成中文:你好
小明听懂了中国人说的:你好