适配器模式(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)
结构
- Target:客户端依赖的目标接口(如 “需要 5V 电压”)。
- Adaptee:被适配的类(如 “提供 220V 电压”)。
- 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,只需持有多个实例)
结构
- Target:同前,客户端依赖的目标接口。
- Adaptee:同前,被适配的类。
- 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 是多个方法的接口,但客户端仅需使用其中部分方法时,通过 “抽象适配器类” 提供接口的默认空实现,客户端继承该抽象类后仅重写需要的方法,避免实现所有接口方法的冗余。
结构
- Target(多个方法的接口):定义了大量方法(如 “多种电压输出接口”)。
- Abstract Adapter(抽象适配器):实现 Target 接口,对所有方法提供默认空实现。
- 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. 继承 vs 组合(类适配器 vs 对象适配器)
| 对比维度 | 类适配器(继承) | 对象适配器(组合) |
|---|---|---|
| 耦合度 | 高(强依赖 Adaptee) | 低(弱依赖,可动态替换) |
| 灵活性 | 低(仅适配一个 Adaptee) | 高(适配多个 Adaptee) |
| 重写方法 | 支持(直接重写 Adaptee 方法) | 不支持(需扩展 Adaptee 子类) |
| 推荐度 | 低(仅特殊场景用) | 高(主流实现方式) |
五、模式扩展
- 双向适配器:使 Adapter 同时适配 Target 和 Adaptee,既允许 Target 客户端调用 Adaptee,也允许 Adaptee 客户端调用 Target。 实现方式:Adapter 同时实现 Target 和 Adaptee 接口,或持有两者实例。
- 缺省适配器(Default Adapter):即 “接口适配器” 的另一种称呼,核心是提供接口的默认空实现,减少客户端冗余代码。
- 多适配者适配器:对象适配器通过持有多个 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 持有页面实例,管理页面生命周期)。
七、总结
适配器模式是解决 “接口不兼容” 问题的核心方案,其三种实现各有适用场景:
- 类适配器:仅在需重写 Adaptee 方法且无多适配需求时使用(Java 中因单继承限制,慎用)。
- 对象适配器:推荐首选,通过组合实现低耦合、高灵活性,支持多适配者。
- 接口适配器:适用于 “接口方法多且客户端仅需部分方法” 的场景,减少冗余代码。
适配器模式的核心价值在于 “解耦客户端与适配者”,在不修改原有代码的前提下复用现有组件,是系统集成、遗留代码迁移的重要工具