描述
定义
Adapter模式将一个类的接口转换成客户希望的另一个接口,从而使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。Adapter模式又叫包装器Wrapper。
类型
对象结构型模式
类适配器 VS 对象适配器
在软件系统中,由于应用环境的变化, 常常需要将“一些现存的对象”放在新的环境中使用,但是新环境要求的接口是这些现存对象所不满足的。这就需要适配器模式来将现在对象适配到要求的接口上。适配器模式分为类适配器模式和对象适配器模式两种。
类适配器模式
用多重继承来使一个接口适配另外一个,Adapter与Adaptee是继承关系。
-
优点
- Adapter可以只重定义Adaptee的部分行为,相当于子类覆盖实现父类的部分方法;
- 仅引入一个对象,不需要额外的字段来引用Adaptee实例;
-
缺点
- 使用静态定义的类继承方式,高耦合,灵活性低;
- 当要匹配一个类以及所有它的子类时,类Adapter将不能胜任工作;
对象适配器模式
依赖于对象聚合,Adapter与Adaptee是委托关系。
-
优点
- 采用动态定义的 “对象组合”的方式,灵活性高、低耦合;
- 允许一个Adapter与多个Adaptee(即Adaptee本身以及它的所有子类)协同工作;
-
缺点
- 需要引入Adaptee对象实例;
- 重定义Adaptee的行为比较困难,需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身;
类适配器和对象适配器的选择
类适配器采用“多继承”的实现方式,耦合度高。对象适配器采用“对象组合”的方式,耦合度低。总的来说,建议使用对象适配器方式。
适配器模式(Adapter)可扩展为双向适配器模式,双向适配器类既可以把适配者接口转换成目标接口,也可以把目标接口转换成适配者接口(即既可以把Adaptee适配成为Target,也可以把Target适配成为Adaptee)。在两个不同的客户需要在不同的地方查看同一个对象时,适合使用双向适配器。
时序图
实现
主要角色
- Target:定义客户(Client)使用的与特定领域相关的接口;
- Client:与符合目标(Target)接口的对象协作;
- Adaptee:定义一个需要被适配的已经存在的接口;
- Adapter:适配被适配(Adaptee)接口到目标(Target)接口;
示例
-
Target:目标接口
interface Target { void request(); }
-
Adaptee:被适配类
class Adaptee { public void specificRequest() { System.out.println("调用被适配类!"); } }
类适配器模式
-
Adapter:适配器类
class Adapter extends Adaptee implements Target { override public void request() { specificRequest(); } }
-
Client:客户端代码
public class Client { public static void main(String[] args) { Target target = new Adapter(); target.request(); } }
对象适配器模式
-
Adapter:对象适配器类
class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee=adaptee; } override public void request() { adaptee.specificRequest(); } }
-
Client:客户端代码
public class Client { public static void main(String[] args) { Adaptee adaptee = new Adaptee(); Target target = new Adapter(adaptee); target.request(); } }
适用场景
- 需要使用一个已经存在的类,而它的接口不符合你的需求,甚至没有这些类的源代码;
- 想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;
-(仅适用于对象适配器模式)想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
优点
- 客户端通过适配器可以透明地调用目标接口;
- 复用了现存的类,不需要修改原有代码而重用现有的适配者类;
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题;
- 可以为不同的目标接口实现不同的适配器,而不需要修改待适配类;
缺点
- 过多的使用适配器,会让系统非常零乱,代码追溯困难;
- 对类适配器来说,更换适配器的实现过程比较复杂;
相关模式
- Bridge模式
- 结构与对象适配器类似;
- 出发点不同:Bridge目的是将接口部分和实现部分分离,从而对它们可以较为容易也相对独立的加以改变。而Adapter则意味着改变一个已有对象的接口;
- Decorator模式
- 增强了其他对象的功能而同时又不改变它的接口,因此decorator对应用程序的透明性比适配器要好;
- Decorator支持递归组合,而纯粹使用适配器是不可能实现这一点的;
- Proxy模式
- 在不改变它的接口的条件下,为另一个对象定义了一个代理;
- Facade模式
- 意图不同:适配器模式使现存系统与正在设计的系统协同工作,而外观模式则为现存系统提供一个更为方便的访问接口;
- 适配器模式为事后设计,而外观模式则必须事前设计,因为系统依靠于外观;
- 适配器模式没有引入新的接口,而外观模式则定义了一个全新的接口;