一, 意图:
将一个类的接口转化成客户希望的另一个接口。 Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
二, 别名:
Wrapper 包装器
三, 动机:
一些已有的类已经实现了你想要的功能, 但是其接口并不兼容。所以你需要一个Wrapper来复用它们, 方式有两种:
- Adapter模式的类版本:新的wrapper类继承已有类, 用其方法来实现你想要的接口、
- 依赖于多重继承
- Adapter模式的对象版本:将已有类作为wrapper类的一个成员变量, 调用它的方法实现想要的接口
- 依赖于对象组合
- 对比:
- 对象版本的优势
- 可以一次适配所有的子类
- 类版本的优势
- 可以方便地修改适配对象的部分行为(重载)
- 当需要适配多个不同类型的功能时会比较麻烦
- 对象版本的优势
四, 适用性
在以下情况使用Adapter模式:
- 你想使用一个已经存在的类, 而他的接口不符合你的需求
- 你想创建一个可以复用的类, 该类可以与其它不相关的类或者可能还没有实现的类协同工作
- 有很多子类, 你没法一一去匹配它们, 这时你可以创建一个wrapper去适配它们的父类接口(对象Adapter版本)
- 可能会有一系列类似的接口, 它们拥有不同的使用条件。 我们可以创建一个wrapper, 根据不同条件调用不同的接口, 从而只对使用者暴露出一个统一的接口
- 双向适配器: 考虑一种情况, 一边是面向对象的前端程序, 一边是进行运算的后端程序,那么很可能需要一个adapter, 将前端的数据适配给后端, 再将后端得出的结果适配给前端
- 可插入的适配器: 一个实现可能有多个调用者, 它们的调用接口各不相同, 这时就需要一个adapter来进行适配
五, 个人理解:
1,关键点
其关键点在于隐藏: 不改变调用者(client)和实现者(adaptee)的代码, 用适配器(adapter)去隐藏它们之间接口的差异, 使它们能协同工作。
2,实现
两种实现方式
基于多重继承 (类版本)
基于组合(对象版本)
相比较而言, 个人更倾向于使用对象版本, 因为:
1,实际的应用场景可能会比较复杂, 实现者的接口不一定是一个类, 可能是一个service, 也可能是很多个类, 这时对象版本更为灵活
2,继承有可能会引入一些你不想要的方法, 尤其是很多情况下你可能并不了解实现者的其它逻辑, 甚至可能实现者在你进行了继承之后又新增了一些方法。 这些都有可能会影响到adapter的行为。 你无法要求别人去保证接口之外的行为。
3,场景
就使用场景来看, 可能有多种情形, 这取决于实现者和调用者的情况:
- 实现者可能有多个, 可能会修改, 也可能还没有实现
- 调用者可能希望根据条件调用不同的实现, 可能有多个, 也可能是未知的。。
- 而适配器的任务就是将这些差异隐藏, 使调用层和实现层解耦,各自独立地开发,而不用关注对方复杂的逻辑。 只要它们保证自己的对外(adapter)接口不变。
4,应用
在美团的工作中已经不经意地使用过不少适配器模式:
- 在筛选迁移时, 使用一个wrapper服务来兼容新老接口。
- 对于移动端 和 搜索后台, API层就相当于一个适配层。
- 当我们的数据存储层有多种形式(mysql, disk,rpc等)时, 我们通常需要一个适配层来对上层应用屏蔽这些差异