一 概述
在程序世界中,经常会存在现有的程序无法直接使用,需要做适合的变换之后才能适应的情况。这种用于填补“现有的程序”和“所需的程序”之间差异的设计模式就是Adapter(适配器)模式。
适配器有以下两种:
- 类适配器模式(使用继承的适配器)
- 对象适配器模式(使用委托的适配器)在实际开发中对象适配器的使用频率更高。
二 产生的背景
- 例如我们对接其他公司系统的时候他们返回的数据和我们的实体类可能有出入,例如自己公司的用户的电话信息,只有一个电话。公司要同步别人系统的用户数据到自己公司系统,被人设计的用户有多个联系电话,这个时候拿到的数据是不一致的,是否可以通过一个转换类将别人的数据封装为合适自己的呢?那么这个转换类其实就充当了适配器这个角色。
- 又例如你去美国谈生意,不懂英语怎么办?难道你可以英语速学几天内讲一口流利的英语吗?你的客户可以中文速学几天内讲一口流利的中文吗?都不现实。最好的方法就是找翻译,那么这个翻译就是担任了适配器的角色。
- 如果想让额定工作电压是直流12V的笔记本电脑在交流100V的AC电源下工作,应该怎么做呢?通常,我们会使用AC适配器,将家庭用的交流100V电压转换成我们所需要的直流12V电压。这就是适配器的工作,它位于实际情况与需求之间,填补两者之间的差异。
对象适配器模式的类图
三 实现方式
例如用户期待的是Target类调用方法,但是自己提供的类是Adaptee这个类,那么就不符合用户的要求,所有可以通过增加适配器类Adapter来转换,其实就是包装一下。
package com.rabbit.pattern.Adapter;
/**
* 用户期待的接口
*
*/
public class Target {
public void request() {
System.out.println("用户期待的接口");
}
}
package com.rabbit.pattern.Adapter;
/**
* 需要适配的类
*
*/
public class Adaptee {
public void request() {
System.out.println("原本的接口,不合适用户的期待");
}
}
package com.rabbit.pattern.Adapter;
/**
* 适配器类,将不符合用户期待的接口匹配为用户期待的
*
*/
public class Adapter extends Target {
private Adaptee a = new Adaptee();
@Override
public void request() {
//自己处理适配的逻辑
a.request();
}
}
四 总结
优点
- 可以让任何两个没有关联的类一起运行
- 提高了类的复用,想使用现有的类,而此类的接口标准又不符合现有系统的需要。通过适配器模式就可以让这些功能得到更好的复用。
- 增加了类的透明度,客户端只关注结果
- 使用适配器的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。
- 灵活性好。
缺点
- 过多使用会导致系统凌乱,追溯困难(内部转发导致,调用A适配成B)
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
适用场景
- 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
- 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
- 通过接口转换,将一个类插入另一个类系中。
参考博客:https://blog.youkuaiyun.com/sinat_32366329/article/details/79937747
https://segmentfault.com/a/1190000011856448
《图解设计模式》