适配器模式(Adapter Pattern)
一、概念
适配器模式(Adapter Pattern)是指将一个类的接口转换成符合调用方规范的另一个接口,使原本的接口不兼容的类可以一起工作
- 适配器模式又叫做
变压器模式
,也叫做包装模式(Wrapper)
,但是包装模式可不止一个,还包括装饰者模式
。 - 适配器模式有3种实现;
- 默认适配器
- 对象适配器
- 类适配器
二、适配器模式本质
- 原有类方法较难修改或修改风险较高,调用者类又必须使用原有代码功能,但是无法遵守原有方法的接口标准;为了
保持开闭原则,避免对原有类的修改
,可以使用适配器模式作为调用方类和原有功能之间的桥梁。 - 在适配器模式中可以定义一个
包装类xxxAdapter
,包装不兼容接口的对象
,这个包装类指的就是适配器(Adapter)
,它所包装的对象就是适配者(Adaptee)
,即被适配的类
。- 也就是说:当调用者类调用适配器的方法时,
在适配器(Adapter)类的内部将调用适配者适配者(Adaptee)类的方法
,而这个过程对调用者是透明的,调用者类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。
- 也就是说:当调用者类调用适配器的方法时,
三、适配器模式适用场景
- 针对
已经存在的类
,它的方法和需求不匹配(方法结果相同或相似) 的情况。 - 适配器模式
不是软件设计阶段考虑的设计模
式,是随着软件维护
,产生了许多功能类似而接口不相同情况下的一种解决方案。
四、适配器模式角色
- Target(目标抽象类):定义客户类所期望的接口方法(
即适配器将要实现的方法
),可以是一个抽象类或接口
,也可以是具体类
。- 该角色定义把适配者转换为何种接口,也就是我们的期望接口。
- Adaptee(适配者类/源角色):即
被适配的类
,一个现存需要适配的接口,适配者类一般是一个具体类,包含了客户类希望使用的业务方法
,在某些情况下可能没有适配者类的源代码。
- Adapter(适配器类):是一个具体的类,负责
Adaptee(适配者类)
转换成Target(目标抽象类)
进行适配,是适配器模式的核心
,在对象适配器中,它通过继承/实现Target
(目标抽象类)并关联一个Adaptee(适配者类)对象
使二者产生联系。- 通过包装被适配对象(Adaptee),
把原接口转换成目标接口(Target)
- 通过包装被适配对象(Adaptee),
- Client(客户类/调用者):实际需要使用
Adaptee
功能的类
五、代码例子
(一)面向类的适配器
Adapter类 实现 使用stack的函数接口 , 但 调用Deque的函数 实现
Target(目标抽象类):Stack
Adaptee(适配者类/源角色):Deque
Adapter(适配器类):Adapter
(二)面向对象的适配器
Suquence 使用 Stack和Queue 实际通过 操作Deque 来实现接口适配(重点:面向对象是操作Deque)
Target(目标抽象类):Sequence
Adaptee(适配者类/源角色):Deque
Adapter(适配器类):Queue 和 Stack
六、适配器模式的实现方式
(一)类适配器方式
通过继承
关系进行适配,类适配器(Adapter)
一般是通过重写目标抽象类(Target)
的方法进行扩展
(面向类的适配器通过继承转换调用函数接口的方式进行类的适配)
(二)对象适配器方式
通过类的关联关系(组合)
跟被适配对象(Adaptee)
整合,一般适配器(Adapter)
会持有适配者(Adaptee)的引用
,在设计时也比较灵活
(面向对象的适配器通过包含适配器对象直接进行适配)
七、UML图
(一)类适配器方式
(二)对象适配器方式
八、适配器模式的优缺点
(一)优点
- 通过引入一个适配器类来重用现有的适配者类 可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”;
(二)缺点
- 过多使用适配器会使得系统非常凌乱,明明调用的是A接口,内部却被适配成了B接口。因此除非必要,不推荐使用适配器,而是直接对系统重构
九、适配器模式与装饰者模式比较
- 适配器模式与装饰者模式比较类似,但是
装饰者模式主要是添加新的功能
,而适配器模式主要做的是转换工作
。
- 适配器将一个对象
包装
起来以改变其接口;装饰者将一个对象包装
起来以增加新的属性和方法
。
十、适配器模式和代理模式的比较
两者在代码结构上,它们很相似
,都需要一个具体的实现类的实例
。但是它们的目的不一样,代理模式的目的是增强原方法
;适配器模式的目的是适配2个接口
,为的是提供“把鸡包装成鸭,然后当做鸭来使用”,而鸡和鸭它们之间原本没有继承关系。