适配器模式充当两个不兼容接口之间的桥梁,使得原本因接口不匹配而无法协同工作的类能够一起工作。
适配器模式主要涉及三个核心角色:
目标接口(Target):这是客户端期望并使用的接口。它定义了客户端需要调用的方法,是系统业务逻辑所期待的规范;
被适配者(Adaptee):这是已经存在的、功能完备但接口与目标接口不兼容的类或组件。它拥有我们需要的功能,但其方法命名或调用方式不符合当前系统的要求;
适配器(Adapter):这是模式的关键,它实现了目标接口,并在内部持有一个被适配者的实例。适配器的职责是将客户端通过目标接口发起的请求,“翻译”并转发给被适配者的相应方法,最终将结果以目标接口期望的格式返回给客户端
对象适配器采用组合的方式,适配器类持有被适配者的一个对象实例。
假设系统原有 AliPay 和 WechatPay 类,但它们的支付方法名不同。现在需要统一调用接口:
# 被适配者:已有的、接口不统一的类
class AliPay:
def alipay_api(self, amount):
print(f"支付宝支付{amount}元")
class WechatPay:
def wechat_pay_api(self, amount):
print(f"微信支付{amount}元")
# 目标接口:期望的统一支付接口
class TargetPayment:
def pay(self, amount):
pass
# 对象适配器
class PaymentAdapter(TargetPayment):
def __init__(self, payment_object, payment_method_name):
self.payment_object = payment_object # 组合:持有被适配者对象
self.payment_method = payment_method_name
self._check_method()
def _check_method(self):
"""检查被适配对象是否有所需方法"""
if not hasattr(self.payment_object, self.payment_method):
raise AttributeError(f"支付方式不支持: {self.payment_method}")
def pay(self, amount):
# 关键步骤:将目标接口调用适配到具体方法
pay_func = getattr(self.payment_object, self.payment_method)
return pay_func(amount)
# 客户端代码
if __name__ == "__main__":
# 创建被适配者
ali = AliPay()
wechat = WechatPay()
# 创建适配器,统一接口
ali_adapter = PaymentAdapter(ali, "alipay_api")
wechat_adapter = PaymentAdapter(wechat, "wechat_pay_api")
# 客户端通过统一的Target接口调用
ali_adapter.pay(100)
wechat_adapter.pay(200)
在这个例子中,PaymentAdapter 作为适配器,通过组合持有了 AliPay 或 WechatPay 的实例,并将统一的 pay() 方法调用适配到各自的 alipay_api() 或 wechat_pay_api() 方法上。
类适配器通过多继承来实现,适配器类同时继承目标接口(或类)和被适配者。这种方式在 Python 中可行,但增加了类之间的耦合度。
假设有两个公司的员工类,方法相似但接口命名不同。
from abc import ABCMeta, abstractmethod
# 目标接口(A公司协议)
class ACpnStaff(metaclass=ABCMeta):
@abstractmethod
def set_name(self, name):
pass
@abstractmethod
def set_phone(self, phone):
pass
# 被适配者(B公司协议)
class BCpnStaff:
def __init__(self, id):
self.id = id
self.name = ""
self.telephone = ""
def set_name(self, name): # 注意:这里方法名巧合相同,但通常不同
print(f"B协议 setName ..id:{self.id}")
self.name = name
def set_phone(self, phone):
print(f"B协议 setPhone ..id:{self.id}")
self.telephone = phone
# 类适配器 (通过多继承)
class CpnStaffAdapter(ACpnStaff, BCpnStaff):
def __init__(self, id):
# 调用BCpnStaff的初始化
BCpnStaff.__init__(self, id)
# 由于方法名相同,这里可能不需要重写。
# 如果方法名不同,则需要在这里重写目标接口方法,并调用父类(被适配者)的方法。
# 例如:def set_name(self, name): return super().setName(name)
# 客户端
if __name__ == "__main__":
adapter = CpnStaffAdapter("123")
adapter.set_name("张三") # 实际调用的是BCpnStaff.set_name
adapter.set_phone("13800138000")
↶ 返回首页 ↶