如何在Python中实现适配器模式以兼容不同厂商的API类?
在Python中实现适配器模式应优先使用组合而非继承,避免厂商接口变更导致崩溃。需统一请求/响应结构为status、payload、error_message等字段。为不同厂商编写独立适配器类,抽取共性逻辑至基类,用工厂函数返回实例。适配器应统一异常体系,区分网络超时、认证失败等类型,并关闭厂商SDK自带重试避免叠加。
在Python项目中对接不同厂商的API接口,几乎是每个后端开发都会遇到的场景。适配器模式在这里扮演的,就是那个把「方言」翻译成「普通话」的角色。问题在于,适配器的实现方式差异很大,踩过的坑也不少,从继承组合的选择,到响应结构的统一,再到异常处理的边界,每一步都有值得推敲的地方。

适配器模式该用类继承还是组合?
结论很明确:优先用组合,而不是继承。继承会强制让你的适配器绑定到某个具体厂商类的生命周期和接口细节上,一旦对方改了方法名、加了参数,你的子类立马崩掉。组合则只依赖厂商类的公开行为,松耦合,测试的时候也方便 mock。
一个典型的反面案例是写出 class MyAdapter(OldVendorAPI),结果发现 OldVendorAPI 的 send_request() 在新版本里改成了 execute(),而继承来的旧方法根本没被重写——调用时直接抛 AttributeError。正确的做法,是让适配器持有厂商的实例:
class VendorAAdapter:
def __init__(self, vendor_instance):
self._vendor = vendor_instance # 组合,不是继承
如何统一不同厂商的请求/响应结构?
各家厂商返回的字段可以说是五花八门:VendorA 返回 {"status": "success", "data": {...}},VendorB 返回 {"code": 0, "result": {...}}。业务代码如果直接处理这些原始响应,那维护成本堪称灾难。
关键在于定义好你内部约定的输出结构——比如统一用 status、payload、error_message 这三个字段,然后把各厂商的原始响应「翻译」过来:
VendorA的"status" == "success"→ 映射为status=TrueVendorB的"code" == 0→ 同样映射为status=True- 所有异常响应都提取出可读的
error_message,哪怕原始数据是个空字符串或者堆栈片段
这些映射逻辑不要散落在业务层,全都封装在适配器里。业务代码只认 adapter.fetch_user(id) 返回的标准化字典,干净利落。
要不要为每个厂商写独立适配器类?
当然要,但别重复造轮子。共性的逻辑——比如重试、超时封装、日志埋点——抽成基类或工具函数。真正需要放到具体适配器里的,是那些差异逻辑:字段解析、鉴权头构造、错误码映射。
一个常见的陷阱是试图写一个「万能适配器」,在里面加一堆 if-elif 判断厂商类型。结果就是 if vendor_type == "A": ... elif vendor_type == "B": ...。把所有厂商耦合进一个类,新增厂商就得改这个大类,严重违反开闭原则。
更稳妥的做法是这样的
- 定义抽象接口
AbstractAPIAdapter,声明get()、post()等方法 - 为每家厂商写独立实现:
VendorAAPIAdapter、VendorBAPIAdapter - 用工厂函数按配置返回对应的实例:
get_adapter(vendor="a")→ 返回VendorAAPIAdapter(...)
适配器里要不要处理网络异常?
要处理,而且得区分对待。厂商 SDK 自己抛的异常——比如 VendorAConnectionError——和标准库异常(例如 requests.Timeout)语义不同,但上层业务其实只关心一件事:这次调用失败了,是否应该重试?
适配器的职责,是把底层异常统一转化成自定义的异常体系:
- 网络超时 → 抛
APITimeoutError - 认证失败 → 抛
APIAuthError - 厂商返回 404 → 抛
APINotFoundError
这样一来,业务层可以用一致的 except APITimeoutError: 做重试,不用关心底层是 requests 还是 urllib3。需要注意的是,不要吞掉原始异常的 traceback,至少保留 raise APITimeoutError(...) from original_exc,否则排查问题的时候找不到根因。
真实项目里还有一个容易被忽略的细节:厂商 SDK 自身内置的重试机制,和你的适配器层重试可能会叠加,导致同一个请求被莫名其妙地发送三次。一个比较稳妥的做法,是关掉厂商 SDK 的自动重试,只在适配器层统一控制。


































