(2024.07.04 Thur)
适配器模式是一种结构设计模式(structural design pattern),用于两种不兼容的接口做对接和交互,扮演桥的角色,允许不同接口的对象互相合作。简单来说就是改变接口。
适配器模式的主要目标是确保客户端能与不同的类或对象协作,该类/对象起初并未为该客户端设计,因此不管是客户端或是被适配的对象都不需要修改源代码即可实现交互。
组成
适配器模式可分为若干关键部分
- Target interface目标接口:目标接口定义了客户端代码期待的接口(contarct),是适配器需要适应的接口,以确保客户端可以和被适配对象无缝沟通
- adaptee被适配对象:与客户端的借口不兼容的类/分量,是客户端希望连接却无法直接沟通的对象,通常是第三方或遗产服务(legacy service)
- adapter适配器:用于连接目标接口和被适配对象的中介(intermediary),将客户端的调用翻译成被适配对象可以理解和响应的形式
(2024.07.05 Fri)
优势
- 代码复用Code reusabililty:适配器方便了代码复用,通过整合现存的类而无需改变他们的源,减少冗余度
- 单一责任原则principle of single responsibility:适配器模式符合单一责任原则,确保了每个类有清晰和特定的角色,也因此提升了代码组织性和可维护性
- 开闭原则Open/Closed Principle:通过适配现存的接口而非直接修改,适配器结构符合开闭原则,允许在不修改现有代码的情况下扩展代码,提升系统稳定性
- 第三方代码整合:在使用外部库或API的时候,适配器模式方便了他们的整合,保护了代码免于被外部改变,也使得外部的升级带来的影响最小
劣势
- 复杂度:适配器会增加代码复杂度,影响代码可维护度
- 性能overhead:加入的适配层可以引入些许性能overhead,对高性能应用是一个隐患
- 实际的影响:适配器的使用可能产生原始的设计问题,对于接口的不兼容性需要考虑重构
实现方式
适配器的实现方式有两种,1) 对象适配器,2) 类适配器
对象适配器Object Adapter Implementation
先定义一个原始系统
class OldSystem:
def legacy_operation(self):
return "legacy operation"
定义适配器
class Adapter:
def __init__(self, old_system: OldSystem):
self.old_system = old_system
def new_operation(self):
return f"Adapter: {self.old_system.legacy_operation()}"
定义客户端
def client_code(adapter: Adapter):
result = adapter.new_operation()
print(result)
运行代码
if __name__ == "__main__":
old_system = OldSystem()
adapter = Adapter(old_system)
client_code(adapter)
返回结果
Adapter: legacy operation
本案例中,创建了一个Adapter
类,该类以OldSystem
对象作为输入,并提供了一个方法new_operation
,该方法符合目标接口。client_code
方法演示了适配器如何允许客户端与OldSystem
无缝衔接。
类适配器Class Adapter
目标适配器往往作为一个常用的实现方式,而类适配器提供了另一个可行方案。在这个案例中,使用多继承(multiple inheritance)实现适配器行为。
定义OldSystem
class OldSystem:
def legacy_operation(self):
return "Legacy operation"
通过继承方式定义适配器,
class Adapter(OldSystem):
def new_operation(self):
return f"Adapter: {self.legacy_operation()}"
定义客户端
# Client code
def client_code(adapter: Adapter):
result = adapter.new_operation()
print(result)
运行代码
if __name__ == "__main__":
adapter = Adapter()
client_code(adapter)
返回结果
Adapter: Legacy operation
在这个实现的版本中,Adapter
从OldSystem
类和目标接口继承,可覆盖legacy_operation
方法以实现适配行为,而client_code
可保持不变。
对象适配器和类适配器各有优势和妥协,而对两种适配器选择取决于特定的需求和项目的限制。
案例
一个案例是用Python的list实现stack的数据结构
stack方法 | Python list的实现 |
---|---|
S.push(e) | L.append(e) |
S.pop() | L.pop() |
S.top() | L[-1] |
S.is_empty() | len(L) == 0 |
len(S) | len(L) |
具体实现
class ArrayStack:
"""LIFO Stack implementation using a Python list as underlying storage."""
def __init__(self):
"""Create an empty stack."""
self._data = [] # nonpublic list instance
def __len__(self):
"""Return the number of elements in the stack."""
return len(self._data)
def is_empty(self):
"""Return True if the stack is empty."""
return len(self._data) == 0
def push(self, e):
"""Add element e to the top of the stack."""
self._data.append(e) # new item stored at end of list
def top(self):
"""Return (but do not remove) the element at the top of the stack.
Raise Empty exception if the stack is empty."""
if self.is_empty():
raise Empty("Stack is empty")
return self._data[−1] # the last item in the list
def pop(self):
"""Remove and return the element from the top of the stack (i.e., LIFO).
Raise Empty exception if the stack is empty."""
if self.is_empty():
raise Empty("Stack is empty")
return self._data.pop() # remove last item from list
Reference
- Medium, Amir Lavasani
- Data Structures and Algorithms in Python