rokevin
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
  • 适配器模式(Adapter Pattern)

  • 一、适配器模式核心概念(通用)
    • 1. 定义
    • 2. 意图
    • 3. 通用核心组件
  • 二、三种适配器模式详解
    • 1. 类适配器(Class Adapter)
      • 核心逻辑
      • 结构
      • 类图(Mermaid)
      • 时序图(Mermaid)
      • 优点
      • 缺点
      • Java 代码实现(电压转换示例)
      • 输出结果
    • 2. 对象适配器(Object Adapter)
      • 核心逻辑
      • 结构
      • 类图(Mermaid)
      • 时序图(Mermaid)
      • 优点
      • 缺点
      • Java 代码实现(延续电压转换示例)
      • 输出结果
    • 3. 接口适配器(Interface Adapter)
      • 核心逻辑
      • 结构
      • 类图(Mermaid)
      • 优点
      • 缺点
      • Java 代码实现(多电压适配示例)
      • 输出结果
  • 三、适配器模式适用环境
  • 四、模式分析
    • 1. 核心本质
    • 2. 继承 vs 组合(类适配器 vs 对象适配器)
  • 五、模式扩展
  • 六、模式应用(通用 + Android)
    • 1. 通用领域应用
    • 2. Android 中的应用
      • (1)ListView/RecyclerView 的 Adapter
      • (2)Retrofit 的 Converter
      • (3)ViewPager 的 PagerAdapter
  • 七、总结

适配器模式(Adapter Pattern)

适配器模式是结构型设计模式的核心之一,其核心目标是解决接口不兼容问题,让原本因接口差异无法协同工作的类能够一起运行。它如同日常生活中的 “电源转换器”—— 将 220V 市电(被适配者)转换为手机需要的 5V 电压(目标接口),使手机(客户端)能正常充电。

一、适配器模式核心概念(通用)

在展开三种具体适配器前,先明确适配器模式的通用定义、意图等核心要素:

1. 定义

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

2. 意图

  • 解决接口不兼容问题:客户端依赖特定接口(Target),但现有类(Adaptee)的接口与 Target 不匹配。
  • 复用现有组件:无需修改 Adaptee 的源代码(遵循 “开闭原则”),即可让其在新系统中复用。
  • 解耦客户端与适配者:客户端仅依赖 Target 接口,无需感知 Adaptee 的具体实现。

3. 通用核心组件

无论哪种适配器,都包含以下 3 个核心角色(接口适配器略有差异):

角色名称职责描述
Target(目标接口)客户端期望的接口,定义了客户端需要的业务方法。
Adaptee(被适配者)现有组件(类 / 接口),其接口与 Target 不兼容,但包含客户端需要的核心功能。
Adapter(适配器)核心转换角色,连接 Target 与 Adaptee: - 实现 Target 接口(满足客户端需求); - 关联 Adaptee(复用其核心功能); - 在 Target 方法中转发调用到 Adaptee 的方法。

二、三种适配器模式详解

适配器模式根据 “Adapter 与 Adaptee 的关联方式” 分为三类:类适配器(继承)、对象适配器(组合)、接口适配器(默认实现)。

1. 类适配器(Class Adapter)

核心逻辑

通过继承 Adaptee + 实现 Target 接口,使 Adapter 同时具备两者特性,从而实现接口转换。 (注:Java 中因 “单继承” 限制,类适配器仅能适配一个 Adaptee)

结构

  1. Target:客户端依赖的目标接口(如 “需要 5V 电压”)。
  2. Adaptee:被适配的类(如 “提供 220V 电压”)。
  3. Adapter:继承 Adaptee + 实现 Target,重写 Target 方法,内部调用 Adaptee 的方法完成转换。

类图(Mermaid)

classDiagram
    class Target {
        <<Interface>>
        +request(): void  // 客户端需要的方法(如输出5V)
    }

    class Adaptee {
        +specificRequest(): void  // 适配者的方法(如输出220V)
    }

    class ClassAdapter {
        +request(): void  // 实现Target方法,转发到specificRequest
    }

    %% 继承Adaptee
    ClassAdapter --|> Adaptee

    %%实现Target接口
    ClassAdapter ..|> Target

时序图(Mermaid)

sequenceDiagram
    participant Client(客户端)
    participant Target(目标接口)
    participant ClassAdapter(类适配器)
    participant Adaptee(被适配者)

    Client->>Target: 调用request()(需要5V)
    Target->>ClassAdapter: 委托给ClassAdapter的request()
    ClassAdapter->>Adaptee: 调用specificRequest()(获取220V)
    Adaptee-->>ClassAdapter: 返回220V
    ClassAdapter-->>Target: 转换为5V并返回
    Target-->>Client: 返回5V

优点

  • 结构简单:通过继承直接复用 Adaptee 的方法,无需额外持有 Adaptee 实例。
  • 可重写 Adaptee 方法:若 Adaptee 的部分方法不符合需求,可在 Adapter 中直接重写。

缺点

  • 耦合度高:Adapter 与 Adaptee 强耦合(继承关系),Adaptee 修改可能影响 Adapter。
  • 单继承限制:Java 中无法同时适配多个 Adaptee(因只能继承一个类)。
  • 违反 “合成复用原则”:优先使用组合而非继承,类适配器因继承导致灵活性不足。

Java 代码实现(电压转换示例)

// 1. 目标接口(客户端需要5V电压)
public interface Voltage5V {
    int output5V();
}

// 2. 被适配者(现有220V电压源)
public class Voltage220V {
    // 输出220V
    public int output220V() {
        int voltage = 220;
        System.out.println("当前电压:" + voltage + "V(市电)");
        return voltage;
    }
}

// 3. 类适配器(继承220V,实现5V接口)
public class ClassVoltageAdapter extends Voltage220V implements Voltage5V {
    @Override
    public int output5V() {
        // 1. 获取220V电压
        int voltage220 = output220V();
        // 2. 转换为5V(模拟降压逻辑)
        int voltage5 = voltage220 / 44;
        System.out.println("电压转换:" + voltage220 + "V -> " + voltage5 + "V");
        return voltage5;
    }
}

// 4. 客户端(手机,需要5V供电)
public class Phone {
    // 依赖目标接口Voltage5V
    public void charge(Voltage5V voltage5V) {
        int voltage = voltage5V.output5V();
        if (voltage == 5) {
            System.out.println("电压正常,开始充电\n");
        } else {
            System.out.println("电压异常,无法充电\n");
        }
    }

    public static void main(String[] args) {
        Phone phone = new Phone();
        // 通过类适配器获取5V电压
        phone.charge(new ClassVoltageAdapter());
    }
}

输出结果

当前电压:220V(市电)
电压转换:220V -> 5V
电压正常,开始充电

2. 对象适配器(Object Adapter)

核心逻辑

通过组合(持有 Adaptee 实例) + 实现 Target 接口,替代继承关系,是更灵活的适配器实现(推荐使用)。 (支持适配多个 Adaptee,只需持有多个实例)

结构

  1. Target:同前,客户端依赖的目标接口。
  2. Adaptee:同前,被适配的类。
  3. Adapter:实现 Target 接口,内部持有 Adaptee 实例,通过实例调用 Adaptee 的方法。

类图(Mermaid)

classDiagram
    class Target {
        <<Interface>>
        +request(): void
    }

    class Adaptee {
        +specificRequest(): void
    }

    class ObjectAdapter {
        -adaptee: Adaptee  // 持有Adaptee实例(组合)
        +ObjectAdapter(adaptee: Adaptee)
        +request(): void
    }


		%% 实现Target接口
    ObjectAdapter ..|> Target
    
    %% 组合关系(has-a)
    ObjectAdapter o-- Adaptee
    

时序图(Mermaid)

sequenceDiagram
    participant Client
    participant Target
    participant ObjectAdapter
    participant Adaptee

    Client->>Target: 调用request()
    Target->>ObjectAdapter: 委托给ObjectAdapter的request()
    ObjectAdapter->>Adaptee: 调用adaptee.specificRequest()(通过持有实例)
    Adaptee-->>ObjectAdapter: 返回结果
    ObjectAdapter-->>Target: 转换结果并返回
    Target-->>Client: 返回结果

优点

  • 低耦合:Adapter 与 Adaptee 通过组合关联,而非继承,降低依赖关系。
  • 灵活性高:支持适配多个 Adaptee(持有多个实例),且可动态替换 Adaptee。
  • 遵循 “合成复用原则”:优先使用组合,符合设计模式最佳实践。

缺点

  • 结构稍复杂:需额外维护 Adaptee 实例(如通过构造函数注入)。
  • 无法重写 Adaptee 方法:若需修改 Adaptee 的方法,需通过子类扩展 Adaptee,再注入 Adapter。

Java 代码实现(延续电压转换示例)

// 1. Target(Voltage5V)和Adaptee(Voltage220V)同前,无需修改

// 2. 对象适配器(持有Voltage220V实例)
public class ObjectVoltageAdapter implements Voltage5V {
    // 持有被适配者实例(组合)
    private Voltage220V voltage220V;

    // 构造函数注入Adaptee
    public ObjectVoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public int output5V() {
        int voltage5 = 0;
        if (voltage220V != null) {
            // 调用Adaptee实例的方法
            int voltage220 = voltage220V.output220V();
            // 模拟降压
            voltage5 = voltage220 / 44;
            System.out.println("电压转换(对象适配器):" + voltage220 + "V -> " + voltage5 + "V");
        }
        return voltage5;
    }
}

// 3. 客户端
public class Phone {
    public void charge(Voltage5V voltage5V) {
        int voltage = voltage5V.output5V();
        if (voltage == 5) {
            System.out.println("电压正常,开始充电\n");
        } else {
            System.out.println("电压异常,无法充电\n");
        }
    }

    public static void main(String[] args) {
        Phone phone = new Phone();
        // 注入Adaptee实例到对象适配器
        phone.charge(new ObjectVoltageAdapter(new Voltage220V()));
    }
}

输出结果

当前电压:220V(市电)
电压转换(对象适配器):220V -> 5V
电压正常,开始充电

3. 接口适配器(Interface Adapter)

核心逻辑

当 Target 是多个方法的接口,但客户端仅需使用其中部分方法时,通过 “抽象适配器类” 提供接口的默认空实现,客户端继承该抽象类后仅重写需要的方法,避免实现所有接口方法的冗余。

结构

  1. Target(多个方法的接口):定义了大量方法(如 “多种电压输出接口”)。
  2. Abstract Adapter(抽象适配器):实现 Target 接口,对所有方法提供默认空实现。
  3. Concrete Adapter(具体适配器):继承 Abstract Adapter,仅重写客户端需要的方法。

类图(Mermaid)

classDiagram
		
    class MultiVoltageTarget {
        <<Interface>>
        +output5V(): void
        +output12V(): void
        +output24V(): void
        +output36V(): void
    }

    class AbstractVoltageAdapter {
        +output5V(): void  // 默认空实现
        +output12V(): void // 默认空实现
        +output24V(): void // 默认空实现
        +output36V(): void // 默认空实现
    }

    class PhoneAdapter {
        +output5V(): void  // 仅重写需要的5V方法
    }

    class LaptopAdapter {
        +output24V(): void // 仅重写需要的24V方法
    }

		AbstractVoltageAdapter ..|> MultiVoltageTarget
    PhoneAdapter --|> AbstractVoltageAdapter
    LaptopAdapter --|> AbstractVoltageAdapter

优点

  • 减少冗余代码:客户端无需实现接口中不需要的方法。
  • 灵活性高:可根据需求灵活重写特定方法。

缺点

  • 仅适用于 “接口方法较多且客户端仅需部分方法” 的场景,通用性较弱。

Java 代码实现(多电压适配示例)

// 1. 目标接口(多种电压输出)
public interface MultiVoltageTarget {
    void output5V();
    void output12V();
    void output24V();
    void output36V();
}

// 2. 抽象适配器(提供默认空实现)
public abstract class AbstractVoltageAdapter implements MultiVoltageTarget {
    @Override
    public void output5V() {}

    @Override
    public void output12V() {}

    @Override
    public void output24V() {}

    @Override
    public void output36V() {}
}

// 3. 具体适配器1:手机需要5V(仅重写output5V)
public class PhoneVoltageAdapter extends AbstractVoltageAdapter {
    private Voltage220V voltage220V;

    public PhoneVoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public void output5V() {
        int voltage220 = voltage220V.output220V();
        int voltage5 = voltage220 / 44;
        System.out.println("手机适配器:" + voltage220 + "V -> " + voltage5 + "V,供手机充电");
    }
}

// 4. 具体适配器2:笔记本需要24V(仅重写output24V)
public class LaptopVoltageAdapter extends AbstractVoltageAdapter {
    private Voltage220V voltage220V;

    public LaptopVoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public void output24V() {
        int voltage220 = voltage220V.output220V();
        int voltage24 = voltage220 / 9; // 模拟降压
        System.out.println("笔记本适配器:" + voltage220 + "V -> " + voltage24 + "V,供笔记本充电");
    }
}

// 5. 客户端
public class Client {
    public static void main(String[] args) {
        Voltage220V voltage220V = new Voltage220V();

        // 手机充电(使用5V适配器)
        PhoneVoltageAdapter phoneAdapter = new PhoneVoltageAdapter(voltage220V);
        phoneAdapter.output5V();

        // 笔记本充电(使用24V适配器)
        LaptopVoltageAdapter laptopAdapter = new LaptopVoltageAdapter(voltage220V);
        laptopAdapter.output24V();
    }
}

输出结果

当前电压:220V(市电)
手机适配器:220V -> 5V,供手机充电
当前电压:220V(市电)
笔记本适配器:220V -> 24V,供笔记本充电

三、适配器模式适用环境

  1. 接口不兼容场景:现有类的接口与客户端需求的接口不一致,需转换后复用。
  2. 复用遗留组件:旧系统中的组件功能完好,但接口与新系统不匹配,需适配后集成。
  3. 扩展新功能:需为多个具有相似功能但接口不同的类提供统一调用入口(如适配多种支付接口)。
  4. 减少冗余代码:接口方法过多,客户端仅需部分方法(接口适配器场景)。

四、模式分析

1. 核心本质

适配器模式的本质是 “接口转换”,而非 “功能增强”:

  • 与装饰器模式的区别:装饰器不改变接口,仅增强功能;适配器改变接口,不增强核心功能。
  • 与外观模式的区别:外观模式为多个子系统提供统一简化接口(适配 “多个系统” 到 “一个接口”);适配器为单个类转换接口(适配 “一个类” 到 “另一个接口”)。

2. 继承 vs 组合(类适配器 vs 对象适配器)

对比维度类适配器(继承)对象适配器(组合)
耦合度高(强依赖 Adaptee)低(弱依赖,可动态替换)
灵活性低(仅适配一个 Adaptee)高(适配多个 Adaptee)
重写方法支持(直接重写 Adaptee 方法)不支持(需扩展 Adaptee 子类)
推荐度低(仅特殊场景用)高(主流实现方式)

五、模式扩展

  1. 双向适配器:使 Adapter 同时适配 Target 和 Adaptee,既允许 Target 客户端调用 Adaptee,也允许 Adaptee 客户端调用 Target。 实现方式:Adapter 同时实现 Target 和 Adaptee 接口,或持有两者实例。
  2. 缺省适配器(Default Adapter):即 “接口适配器” 的另一种称呼,核心是提供接口的默认空实现,减少客户端冗余代码。
  3. 多适配者适配器:对象适配器通过持有多个 Adaptee 实例,同时适配多个不同接口的类,提供统一的 Target 接口。

六、模式应用(通用 + Android)

1. 通用领域应用

  • Java IO 流:InputStreamReader(将InputStream字节流适配为Reader字符流,对象适配器)、OutputStreamWriter。
  • Spring 框架:AdvisorAdapter(适配不同类型的 Advisor 到 MethodInterceptor 接口)、HandlerAdapter(适配不同 Controller 到 DispatcherServlet)。
  • 数据库驱动:JDBC 驱动适配不同数据库(如 MySQL、Oracle)的接口到 JDBC 标准接口。

2. Android 中的应用

(1)ListView/RecyclerView 的 Adapter

  • 核心逻辑:将 数据源(List<Bean>,Adaptee) 适配为 UI 组件(ListView/RecyclerView,Target) 需要的接口(如getCount()、getView())。
  • 类型:对象适配器(Adapter 持有数据源实例,通过组合复用数据)。
// ListView的BaseAdapter(抽象适配器,简化接口实现)
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    // 提供默认实现,客户端仅需重写getCount()、getView()等核心方法
    @Override
    public int getCount() { return 0; }

    @Override
    public Object getItem(int position) { return null; }

    @Override
    public long getItemId(int position) { return position; }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) { return null; }
}

(2)Retrofit 的 Converter

  • 核心逻辑:将 “网络响应的 JSON 字符串(Adaptee)” 适配为 “Java 实体类(Target)”,或反之(请求时将实体类转为 JSON)。
  • 类型:对象适配器(Converter 持有 Gson/Moshi 等解析器实例,完成格式转换)。

(3)ViewPager 的 PagerAdapter

  • 核心逻辑:将 “页面视图(View/Fragment,Adaptee)” 适配为 “ViewPager(Target)” 需要的接口(如instantiateItem()、destroyItem())。
  • 类型:对象适配器(PagerAdapter 持有页面实例,管理页面生命周期)。

七、总结

适配器模式是解决 “接口不兼容” 问题的核心方案,其三种实现各有适用场景:

  1. 类适配器:仅在需重写 Adaptee 方法且无多适配需求时使用(Java 中因单继承限制,慎用)。
  2. 对象适配器:推荐首选,通过组合实现低耦合、高灵活性,支持多适配者。
  3. 接口适配器:适用于 “接口方法多且客户端仅需部分方法” 的场景,减少冗余代码。

适配器模式的核心价值在于 “解耦客户端与适配者”,在不修改原有代码的前提下复用现有组件,是系统集成、遗留代码迁移的重要工具

最近更新:: 2025/10/22 15:36
Contributors: 罗凯文, luokaiwen