DEV Community

架构师小白
架构师小白

Posted on

适配器模式深度指南:让不兼容接口和谐共存的艺术

适配器模式深度指南:让不兼容接口和谐共存的艺术

在软件开发中,我们经常会遇到这样的困境:现有的类库、第三方组件或遗留系统的接口与我们需要的不兼容。直接修改源代码可能不现实,甚至会带来风险。这时,适配器模式(Adapter Pattern)就是我们解决问题的利器。

什么是适配器模式?

适配器模式是一种结构型设计模式,它的核心思想是:将一个类的接口转换成客户端所期望的另一个接口。适配器让原本接口不兼容的类可以协同工作。

生活中的适配器

其实适配器在我们生活中无处不在:

  • 手机充电器:220V 交流电 → 5V 直流电(电源适配器)
  • HDMI 转 VGA:数字信号 → 模拟信号(视频转换器)
  • 蓝牙耳机适配器:让不支持蓝牙的设备也能使用蓝牙耳机

这些适配器的共同特点是:它们不改变被适配对象的本质,只是让它们能够适应新的环境

适配器模式的结构

适配器模式主要有两种实现方式:

1. 类适配器(通过继承)

# 目标接口
class Target:
    def request(self) -> str:
        return "Target: Default behavior"

# 被适配者(Adaptee)
class Adaptee:
    def specific_request(self) -> str:
        return ".eetpadA eht fo roivaheb laicepS"

# 类适配器
class ClassAdapter(Adaptee, Target):
    def request(self) -> str:
        # 反转字符串来模拟适配
        return f"ClassAdapter: (TRANSLATED) {self.specific_request()[::-1]}"
Enter fullscreen mode Exit fullscreen mode

2. 对象适配器(通过组合)

# 对象适配器 - 更常用、更灵活
class ObjectAdapter(Target):
    def __init__(self, adaptee: Adaptee):
        self._adaptee = adaptee

    def request(self) -> str:
        return f"ObjectAdapter: (TRANSLATED) {self._adaptee.specific_request()[::-1]}"
Enter fullscreen mode Exit fullscreen mode

实战案例

案例一:集成第三方支付系统

假设我们定义了一个统一的支付接口:

from abc import ABC, abstractmethod

class PaymentGateway(ABC):
    @abstractmethod
    def pay(self, amount: float) -> dict:
        pass

    @abstractmethod
    def refund(self, transaction_id: str) -> dict:
        pass
Enter fullscreen mode Exit fullscreen mode

现在需要集成一个旧的第三方支付系统:

class LegacyPaymentSystem:
    def make_payment(self, amount_cents: int, currency: str) -> str:
        # 旧系统使用分作为单位
        return f"TXN-{amount_cents}-{currency}"

    def process_refund(self, order_id: str) -> bool:
        return True

# 创建适配器
class LegacyPaymentAdapter(PaymentGateway):
    def __init__(self):
        self._legacy = LegacyPaymentSystem()

    def pay(self, amount: float) -> dict:
        # 转换:元 → 分
        amount_cents = int(amount * 100)
        transaction_id = self._legacy.make_payment(amount_cents, "CNY")
        return {
            "success": True,
            "transaction_id": transaction_id,
            "amount": amount
        }

    def refund(self, transaction_id: str) -> dict:
        # 提取订单信息并退款
        success = self._legacy.process_refund(transaction_id)
        return {"success": success}
Enter fullscreen mode Exit fullscreen mode

案例二:数据格式转换

import json
from xml.etree import ElementTree as ET

# 旧的 XML 数据源
class XMLDataSource:
    def get_data(self) -> str:
        return """<?xml version="1.0"?>
        <user>
            <name>张三</name>
            <email>zhangsan@example.com</email>
        </user>"""

# 目标接口:JSON 格式
class JSONDataSource(ABC):
    @abstractmethod
    def get_json_data(self) -> dict:
        pass

# XML 转 JSON 适配器
class XMLToJSONAdapter(JSONDataSource):
    def __init__(self, xml_source: XMLDataSource):
        self._xml_source = xml_source

    def get_json_data(self) -> dict:
        xml_str = self._xml_source.get_data()
        root = ET.fromstring(xml_str)

        return {
            "name": root.find("name").text,
            "email": root.find("email").text
        }
Enter fullscreen mode Exit fullscreen mode

适配器模式的优缺点

✅ 优点

  1. 单一职责原则:将接口转换逻辑分离到适配器中
  2. 开闭原则:在不修改原有代码的情况下集成新组件
  3. 提高复用性:让现有的类能够适应新的需求
  4. 解耦:客户端与具体实现解耦

❌ 缺点

  1. 增加复杂性:引入额外的适配器层
  2. 性能开销:每次调用都有转换成本
  3. 过度使用风险:不要滥用适配器,优先考虑重构接口

适配器 vs 装饰器 vs 桥接模式

模式 目的 关系
适配器 让不兼容的接口变得兼容 转换已有接口
装饰器 动态添加职责 增强功能
桥接 分离抽象与实现 解耦维度

最佳实践

  1. 优先使用对象适配器:通过组合实现,更灵活
  2. 适配器应该是透明的:客户端不应该感知适配器的存在
  3. 考虑使用依赖注入:让适配器更容易测试
  4. 不要滥用:如果可以修改接口,优先重构而非添加适配器

总结

适配器模式是解决接口不兼容问题的经典方案,它就像现实世界中的各种转换器,让不同的系统能够协同工作。在实际开发中,当我们需要在不修改现有代码的前提下集成新的组件或服务时,适配器模式是一个非常实用的选择。

记住:适配器是桥梁,让不兼容变成可能


本文是软件架构系列文章的一部分,欢迎关注更多设计模式的深度指南。

Top comments (0)