适配器模式
1/10/24About 5 min
Adapter,可以充当两个类之间的媒介,它可以转换一个类的接口,这样就可以被另外一个类使用,这使得具有不兼容接口的类能够协同使用。Adapter模式实现为客户端所知的接口,并且为客户端提供对不为其所知的类实例的访问。Adapter对象可以在不知道实现该接口的类的情况下,提供该接口的功能。

适配器模式允许两个或多个不兼容的对象进行交互通信,提高已有功能的重复使用性。
以下几种情况应该使用适配器模式。
- 要使用已有类,而该类接口与所需的接口并不匹配。
- 要创建可重用的类,该类可以与不相关的未知类进行协作,也就是说,类之间并不需要兼容接口。
- 要在一个不同于已知对象接口的接口环境中使用对象。
- 必须要进行多个源之间的接口转换的时候。
代码实现
已有类的实现
假设系统中已经存在了Adaptee类,并且该类实现了某种功能,或者具有某些我们需要的属性。
public class Adaptee {
public void specificRequest() {
System.out.println("Specific request");
}
}目标类的接口
现在需要新增一个接口以及该接口对应的功能,如下。
public abstract class Target {
public abstract void request();
}适配器
我们需要一个适配器类,该类实现了目标类的接口,并且将Adaptee类中的方法进行适配,如下。
public class Adapter extends Target {
private Adaptee adaptee;
@Override
public void request() {
adaptee = new Adaptee();
adaptee.specificRequest();
}
}使用
public class AdapterClient {
public static void main(String[] args) {
Target target = new Adapter();
target.request();
}
}
## 与其他设计模式的对比
### 适配器模式 vs 装饰器模式
| 特性 | 适配器模式 | 装饰器模式 |
|------|----------|------------|
| 目的 | 改变接口以兼容不同的客户端 | 在不改变接口的情况下增强功能 |
| 接口变化 | 改变原有类的接口 | 保持原有类的接口不变 |
| 功能变化 | 不添加新功能,只转换接口 | 添加新功能,增强原有对象 |
| 组合方式 | 持有被适配对象的引用 | 继承或包装原有对象 |
| 适用场景 | 接口不兼容的场景 | 需要动态增强功能的场景 |
### 适配器模式 vs 代理模式
| 特性 | 适配器模式 | 代理模式 |
|------|----------|------------|
| 目的 | 改变接口以兼容不同的客户端 | 控制对原有对象的访问 |
| 接口变化 | 改变原有类的接口 | 保持原有类的接口不变 |
| 功能变化 | 不添加新功能,只转换接口 | 可以添加额外的控制逻辑 |
| 客户端感知 | 客户端不感知被适配对象 | 客户端感知代理对象 |
| 适用场景 | 接口不兼容的场景 | 需要控制访问的场景 |
### 适配器模式 vs 外观模式
| 特性 | 适配器模式 | 外观模式 |
|------|----------|------------|
| 目的 | 改变单个类的接口 | 为多个类提供统一的接口 |
| 接口数量 | 一对一的接口转换 | 一对多的接口统一 |
| 功能变化 | 不添加新功能,只转换接口 | 可能简化或组合多个类的功能 |
| 客户端感知 | 客户端与适配器交互 | 客户端与外观交互,不感知内部类 |
| 适用场景 | 接口不兼容的场景 | 需要简化复杂系统接口的场景 |
## 总结
适配器模式是一种结构型设计模式,它允许将一个类的接口转换成客户端期望的另一个接口,使得原本不兼容的类能够协同工作。
### 核心思想
适配器模式的核心思想是通过创建一个适配器类,作为两个不兼容接口之间的桥梁,将一个类的接口转换成客户端能够理解和使用的另一个接口。
### 主要角色
1. **目标接口(Target)**:客户端期望的接口
2. **被适配者(Adaptee)**:已存在的、但接口与目标接口不兼容的类
3. **适配器(Adapter)**:实现目标接口,并持有被适配者的引用,负责将客户端的请求转发给被适配者
### 实现方式
1. **类适配器**:通过继承被适配者类并实现目标接口来实现适配
2. **对象适配器**:通过持有被适配者对象的引用并实现目标接口来实现适配(更常用,因为遵循合成复用原则)
### 优点
- **提高复用性**:可以复用已有的类,无需修改其代码
- **提高扩展性**:可以方便地引入新的适配器来支持新的类型
- **解耦客户端和被适配者**:客户端只与目标接口交互,不直接依赖于被适配者
- **灵活性高**:可以在运行时选择不同的适配器
### 缺点
- **增加系统复杂性**:引入了额外的适配器类
- **可能降低性能**:适配器的转发过程可能会带来一定的性能开销
- **设计难度增加**:需要正确识别目标接口和被适配者之间的差异
### 适用场景
- **集成已有系统**:当需要集成已有的类,但接口不兼容时
- **复用遗留代码**:当需要复用遗留系统的代码,但接口不符合新系统的要求时
- **跨平台兼容**:当需要在不同平台之间提供兼容层时
- **第三方库集成**:当需要使用第三方库,但接口与系统不兼容时
### 实际应用
在实际开发中,适配器模式常用于:
- Java中的JDBC驱动程序(将不同数据库的API适配到JDBC接口)
- Spring框架中的各种适配器(如HandlerAdapter)
- GUI开发中的事件适配器(如MouseAdapter、KeyAdapter)
- 数据格式转换(如JSON与XML之间的转换)