什么是 适配器模式?
适配器模式
(
Adapter pattern
)是一种结构型设计模式,帮助我们实现两个不兼容接口之间 的兼容。首先,解释一下不兼容接口的真正含义。如果我们希望把一个老组件用于一个新系统中, 或者把一个新组件用于一个老系统中,不对代码进行任何修改两者就能够通信的情况很少见。但 又并非总是能修改代码,或因为我们无法访问这些代码(例如,组件以外部库的方式提供),或 因为修改代码本身就不切实际。在这些情况下,我们可以编写一个额外的代码层,该代码层包含 让两个接口之间能够通信需要进行的所有修改。这个代码层就叫适配器。
客户端 不想 修改现有代码,不关心 适配细节,以及适配了什么,只关心 怎么调用,以及调用结果符合预期 即可;
代码中的例子(何时该使用此模式):
- 开发人员在通过 sqlalchemy 操作mysql时,开发人员 想使用ORM方式操作数据库,则sqlalchemy对具体数据库进行适配;从而 用户不必手写具体sql语句,直接对 sqlalchemy进行操作即可;
- 一个 只接收 dict类型数据 的 算法函数, 但是目前 突然多了一个 yaml文件格式的数据,则 需要定义一个 yaml格式转为 dict的 适配器,然后供 算法函数调用
- python调用 一个 R语言算法库 获取算法结果; 需要编写一个 适配器,提供 一个对外的接口,python调用此接口,接口内部实现调用 R语言算法库;这时 python调用 适配器接口,完全不care R语言算法库内部实现逻辑,甚至连 R语言语法都不需要懂
适配器模式 关键的角色:
- 客户端 (Client) 用来 调用 固定接口的 角色
- 服务 (Service) 中有一些功能类 (通常来自第三方或遗留系统)。 客户端与其接口不兼容, 因此无法直接调用其功能。
- 适配器 (Adapter) 是一个可以同时与客户端和服务交互的类: 它在实现客户端接口的同时封装了服务对象。 适配器接受客户端通过适配器接口发起的调用, 并将其转换为适用于被封装服务对象的调用。
该模式的主要优缺点如下:
示例代码部分
函数 参数 问题 的适配器
def calculate(a, b):
"""
计算 2个数字 之和,且2个参数 不能为空
service:被 适配的 函数
:param a:
:param b:
:return:
"""
return a + b
def calculate_adapter(a, b=None):
"""
对 入参进行 适配,使其 能够调用 calculate函数
adapter:
:param a:
:param b:
:return:
"""
if not b:
b = a
return calculate(a, b)
if __name__ == '__main__':
"""
客户端 的需求 是 只想 计算 某个数字 本身 相加的和 ,且 就是 不想 输入2遍相同的参数;于是 只能 添加适配器,然后调用适配器 来解决问题
"""
a = 1
# 客户端调用适配代码
print(calculate_adapter(a))
总结:
适配器 模式 用在 修改 对方的代码(sdk包,单独的服务,已经被多处调用 等条件) 比较麻烦耗时, 为了 节约时间,减少更改现有客户端代码出现的 安全性问题 等等, 只能 通过适配器的 方式 来快速的 完成业务需求; 但是 如果过多使用 适配器,导致代码高度抽象,难以维护, 所以 条件允许时,没必要 非要为了 所谓 开闭原则 而 增加额外 适配器代码(如上代码示例,客户端需求完全是傻逼需求);
适配器 模式 是 对 被适配service 的一种伪装;就像披着羊皮的狼, 牧羊人(client角色) 叫 羊赶回家,其实归根到底 还是 把狼带回了家; 而且 可悲的是 牧羊人还不知道(client对适配的内容不知道);
而 装饰器 模式 则是 对 被装饰 对象 提供的 额外的功能;比如 给 羔羊 添加 铜皮铁骨 的 功能,这样 就不怕狼来了;
相关链接:
https://refactoringguru.cn/design-patterns/adapter
https://refactoringguru.cn/design-patterns/adapter/python/example
http://c.biancheng.net/view/1361.html