一、Adapter(适配器)设计模式

1、模式概述

适配器模式(Adapter Pattern 是一种 结构型设计模式,其核心目标是:

适配器模式 = 接口翻译官:

  • 将一个类的接口转换成客户端所期望的另一个接口,使原本因接口不兼容而不能一起工作的类可以协同工作。

  • 它不做功能增强,也不改变行为,只是 在不修改原有代码的前提下,让不兼容的接口“说同一种语言”

1)两种实现方式

类型 实现机制 特点
类适配器 通过 继承 被适配类(Adaptee 仅适用于支持多重继承的语言(如 C++),Java 中因单继承限制使用较少
对象适配器 通过 组合/委托 持有被适配对象 更灵活、推荐方式,符合“组合优于继承”原则

2)适配器 vs 装饰器:关键区别

两者都被称为 包装模式(Wrapper Pattern),但目的截然不同:

  • 适配器:“让它能用”(接口不匹配 → 匹配)
  • 装饰器:“让它更好用”(功能不足 → 增强)
模式 目的 接口变化 典型用途
Adapter(适配器) 转换接口,解决兼容性问题 改变或统一接口(旧 → 新) 集成遗留系统、第三方库封装
Decorator(装饰器) 增强功能,动态添加职责 保持原有接口不变 日志、缓存、权限校验等横切关注点

3)使用场景

  • 需要使用一个已存在的类,但其接口不符合当前需求;
  • 想创建一个可复用的类,与不相关或不可预见的类协同工作;
  • 需要适配多个已有子类,但不想为每个子类编写适配逻辑(可用对象适配器统一处理)。

在实际开发中:

  • 优先使用对象适配器(组合)
  • 当需要适配多个相似类时,可结合 工厂模式 动态创建适配器;
  • Java 标准库中的 Arrays.asList()InputStreamReader 等都是适配器的经典应用。

2、示例场景:电压适配类比

我们有一个 100V 的电器(Banner),但插座提供的是 220V 接口(Print)

通过 适配器(Adapter),我们让 100V 设备“看起来像”支持 220V 接口,从而无缝接入系统。

1)被适配的现有类(Adaptee

这是已存在的类,无法修改或不应修改(如第三方库)。

/**
 * Adaptee(被适配者)—— 现有系统中的类,接口不符合新需求
 */
public class Banner {
    private final String text;

    public Banner(String text) {
        this.text = text;
    }

    public void showWithParen() {
        System.out.println("(" + text + ")");
    }

    public void showWithAster() {
        System.out.println("*" + text + "*");
    }
}

2)目标接口(Target

/**
 * Target(目标接口)—— 客户端期望的接口
 */
public interface Print {
  
    void printWeak();   // 弱调用 → 对应 (text)
  
    void printStrong(); // 强调用 → 对应 *text*
}

3)方式一:类适配器(继承)

  • Java 不支持多重继承,若 Banner 已继承其他类,则无法使用此方式。
  • 违反“合成复用原则”。

1558686754766

/**
 * Class Adapter:通过继承 Banner 并实现 Print 接口
 */
public class PrintBanner extends Banner implements Print {

    public PrintBanner(String text) {
        super(text);
    }

    @Override
    public void printWeak() {
        showWithParen();
    }

    @Override
    public void printStrong() {
        showWithAster();
    }
}

4)方法2:对象适配器(委托/组合) 推荐

  • 灵活,可适配任意 Banner 子类
  • 符合开闭原则(对扩展开放,对修改关闭)
  • 支持运行时动态替换被适配对象
/**
 * Object Adapter:通过组合 Banner 实现适配
 */
public class PrintBanner implements Print {
    private final Banner banner;

    public PrintBanner(String text) {
        this.banner = new Banner(text);
    }

    @Override
    public void printWeak() {
        banner.showWithParen();
    }

    @Override
    public void printStrong() {
        banner.showWithAster();
    }
}

5) 客户端测试

客户端 完全不知道 Banner 的存在,只与 Print 接口交互,实现了 解耦

public class Main {
    public static void main(String[] args) {
        Print printer = new PrintBanner("Hello");

        printer.printWeak();   // 输出: (Hello)
        printer.printStrong(); // 输出: *Hello*
    }
}

3、模式角色总结

角色 职责 示例
Target(目标接口) 定义客户端使用的接口 Print
Adaptee(被适配者) 已存在的、接口不兼容的类 Banner
Adapter(适配器) 转换 Adaptee 接口为 Target 接口 PrintBanner
Client(客户端) 使用 Target 接口完成业务逻辑 Main

1)UML 类适配器模式(使用继承)

1558689013642

2)UML 对象适配器模式(使用委托)

1558689101738