Skip to content

适配器模式(Adapter Pattern)

1. 官方定义

"Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces."
—— 《Design Patterns: Elements of Reusable Object-Oriented Software》(GoF, 1994)

核心:将一个类的接口转换为客户端期望的另一个接口,使原本因接口不兼容而无法协作的类能够协同工作。

2. 模式解释

核心思想

  • 接口转换:通过中间层(适配器)解决新旧系统或第三方组件的接口不兼容问题。
  • 透明集成:客户端仅依赖目标接口,无需感知适配器背后的复杂转换逻辑。

典型结构

plaintext
          Client → |<<Interface>>|  
                     Target  

                        |  
               ┌────────┴────────┐  
               |                 |  
      ObjectAdapter      ClassAdapter  
  (持有Adaptee实例)        (继承Adaptee)
               |                 |  
               ▼                 ▼  
           Adaptee           Adaptee

优点

  • 复用性:集成不兼容的现有类或第三方库。
  • 解耦性:客户端代码与具体实现解耦,仅依赖目标接口。
  • 灵活性:支持多个适配器处理不同接口变体(如不同版本的 API)。

缺点

  • 过度适配风险:滥用可能导致系统复杂度增加(如嵌套多层适配器)。
  • 性能损耗:适配器转发调用可能引入额外开销(如网络请求代理)。

3. 解决的问题

经典场景

  1. 第三方库集成
    • 旧系统调用新支付接口(如支付宝接口适配银行遗留系统)。
  2. 接口版本升级
    • 新版 API 兼容旧版客户端(如 V2APIAdapter 包装 V3API)。
  3. 跨平台兼容
    • 统一不同数据格式(如 XML 转 JSON 适配器)。

4. 实现注意事项

关键实现点

  1. 适配器类型选择
    • 类适配器:通过多重继承实现(Java 不支持,C++ 适用),直接继承被适配类。
    • 对象适配器:通过组合持有被适配对象实例(推荐方式,更灵活)。
  2. 接口匹配粒度
    • 适配器可能需聚合多个被适配类的方法(如合并 LegacyDB.read()NewDB.query())。
  3. 异常处理
    • 转换过程中需处理接口差异导致的异常(如字段缺失、类型不匹配)。

代码示例(对象适配器)

java
// 目标接口(客户端期望的接口)
interface ModernPrinter {
    void print(String text);
}

// 被适配类(已有但不兼容的类)
class LegacyPrinter {
    void printDocument(String content, int copies) {
        for (int i=0; i<copies; i++) {
            System.out.println(content);
        }
    }
}

// 对象适配器
class PrinterAdapter implements ModernPrinter {
    private LegacyPrinter legacyPrinter;

    public PrinterAdapter(LegacyPrinter printer) {
        this.legacyPrinter = printer;
    }

    @Override
    public void print(String text) {
        legacyPrinter.printDocument(text, 1); // 固定 copies=1
    }
}

// 客户端调用
ModernPrinter printer = new PrinterAdapter(new LegacyPrinter());
printer.print("Hello Adapter!");

5. 实现变体

类型特点适用场景
对象适配器通过组合持有被适配对象(推荐)需适配多个类或子类
类适配器通过继承被适配类(需语言支持多重继承)简单适配且无需运行时动态切换
双向适配器同时实现两个接口,支持双向转换新旧系统需互相调用

6. 相似模式对比

模式核心区别
桥接模式分离抽象与实现,适配器模式解决已有接口不兼容问题
装饰者模式增强对象功能,适配器模式改变对象接口
外观模式简化复杂子系统接口,适配器模式解决接口不匹配

7. 组合使用场景

常见搭配模式

  1. 工厂模式
    • 场景:由工厂类决定生成哪种适配器(如根据配置选择 XML/JSON 适配器)。
  2. 装饰者模式
    • 场景:在适配过程中添加额外功能(如日志记录、缓存)。
  3. 代理模式
    • 场景:远程调用时适配不同协议(如 REST 到 gRPC 的适配代理)。

8. 总结与关键词

关键词

  • 适配器模式 (Adapter Pattern)
  • 设计模式 (Design Patterns)
  • 接口转换 (Interface Conversion)
  • 对象适配器 (Object Adapter)
  • 类适配器 (Class Adapter)
  • 第三方集成 (Third-Party Integration)

总结

  • 核心价值:通过中间层解决接口不兼容问题,实现系统间无缝协作。
  • 适用场景:集成遗留代码、第三方库或处理多版本接口兼容。
  • 实现选择:优先使用对象适配器(组合优于继承),慎用多重继承。
  • 经典案例
    • Java 的 InputStreamReader(适配 InputStreamReader)。
    • Spring 的 HandlerInterceptorAdapter(简化拦截器实现)。

附:适配器模式 vs 外观模式

模式目标复杂度
适配器接口转换(一对一映射)通常较简单
外观简化接口(聚合多个子系统)可能较复杂

通过合理使用适配器模式,可显著降低系统重构成本,提升组件复用性,是应对接口差异的核心设计工具。