适配器模式:接口不兼容时的转换器
FreeGuideOnline
最新
2026-06-18
适配器模式:接口不兼容时的转换器
1. 什么是适配器模式?
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将某个类的接口转换为客户端期望的另一个接口,从而使原本因接口不匹配而无法一起工作的两个类能够协同工作。
你可以把它想象成现实世界中的电源转换插头:一个美标的电子产品带到中国,插头形状不同,电压可能也不同。你不需要拆开电器修改电路,只需买一个转换插头,就能把美标插头“适配”成符合中国标准的插头,让电器正常使用。适配器模式做的就是同样的事情——封装一个已有的不兼容接口,并提供客户端需要的接口。
2. 为什么需要适配器模式?
- 你想使用一个已经存在的类,但它的接口与你当前系统要求的接口不一致。
- 你想创建一个可复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
- 你需要使用多个现有子类,但是逐个适配每个子类的接口太麻烦,可以为这些子类创建一个统一的适配器接口来封装它们。
适配器模式的核心思想是:不修改原有代码,而是增加一个中间层进行接口转换,符合开闭原则。
3. 适配器模式的结构
适配器模式有两种常见实现形式:
- 对象适配器(Object Adapter):适配器持有被适配者的实例,通过组合实现适配。
- 类适配器(Class Adapter):适配器通过多重继承(Java中需接口+继承,其他语言可能用多重继承)同时获得目标接口和被适配者的行为。
由于对象适配器使用更广泛(避免了多重继承的局限),本文主要讲解对象适配器。
参与者角色
- Client(客户端):只认识目标接口,调用目标接口的方法。
- Target(目标接口):客户端期望使用的接口,可以是一个抽象类或接口。
- Adaptee(被适配者):已经存在的、需要被适配的类,它的接口与目标接口不兼容。
- Adapter(适配器):实现了目标接口,并在内部包装了一个 Adaptee 对象,将 Target 的请求转换为 Adaptee 可以理解的请求。
4. 如何实现适配器模式?
假设你有一个旧版的温度传感器类(OldThermometer),它以华氏度返回温度。但你的新监控系统要求所有传感器提供摄氏度的接口(CelsiusSensor)。你不能直接修改旧硬件驱动,于是创建一个适配器。
步骤:
- 定义客户端期望的目标接口
CelsiusSensor。 - 已有的
OldThermometer作为被适配者。 - 创建适配器类
ThermometerAdapter,实现CelsiusSensor,同时持有OldThermometer的引用。 - 在适配器的
getTemperatureCelsius()方法中,调用OldThermometer的getFahrenheit()并完成温度转换。
Java 示例
// 目标接口:客户端期望的温度传感器(摄氏度)
interface CelsiusSensor {
double getTemperatureCelsius();
}
// 被适配者:已有的旧温度计,只能返回华氏度
class OldThermometer {
public double getFahrenheit() {
// 模拟返回一个华氏温度值
return 98.6;
}
}
// 适配器:实现目标接口,内部包装 OldThermometer
class ThermometerAdapter implements CelsiusSensor {
private OldThermometer oldThermometer;
public ThermometerAdapter(OldThermometer oldThermometer) {
this.oldThermometer = oldThermometer;
}
@Override
public double getTemperatureCelsius() {
// 将华氏度转换为摄氏度
double fahrenheit = oldThermometer.getFahrenheit();
return (fahrenheit - 32) * 5 / 9;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
OldThermometer oldThermo = new OldThermometer();
CelsiusSensor sensor = new ThermometerAdapter(oldThermo);
System.out.println("温度:" + sensor.getTemperatureCelsius() + " °C");
}
}
输出: 温度:37.0 °C
5. 类适配器与对象适配器的区别
- 对象适配器(推荐):使用组合,适配器持有 Adaptee 实例。更灵活,因为被适配者的子类也可以通过同一个适配器工作。
- 类适配器:使用继承(或接口+继承),适配器同时继承 Target 和 Adaptee。在某些语言(如 C++)中可以实现私有继承,但在 Java 中难以做到纯粹的多重继承,通常需要 Adaptee 是类而 Target 是接口,适配器实现接口并继承 Adaptee。缺点是耦合度高,且只能适配一个具体的 Adaptee 类及其子类。
对象适配器示例代码(Java): 已在上方展示。
类适配器示例(Java,假设 Target 是接口):
// 目标接口
interface Target {
void request();
}
// 被适配者
class Adaptee {
public void specificRequest() {
System.out.println("被适配者的方法执行");
}
}
// 类适配器:实现接口,同时继承 Adaptee
class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
// 直接调用继承自 Adaptee 的方法
specificRequest();
}
}
6. 适配器模式的真实世界应用
- JDBC 驱动:Java 中 JDBC 为数据库访问定义了一套标准接口(Target),每个数据库厂商提供一个驱动适配器,将 JDBC 接口的调用转换为自身数据库的私有协议(Adaptee)。
- 电源适配器:将交流电(220V)转换为不同设备需要的直流电压。
- 遗留系统集成:当新系统需要调用旧系统的功能,但旧系统的 API 风格或方法签名不匹配时,写一个适配器层来封装旧代码。
- 不同支付网关的整合:第三方支付服务提供不同的接口,我们可以为每一家支付服务编写适配器,实现统一支付接口,方便切换。
7. 适配器模式的优缺点
优点:
- 复用已有类:无需修改原有代码,就能复用现有功能。
- 解耦:客户端只依赖目标接口,与具体的被适配者解耦。
- 增加透明度:使用者不知道具体的适配操作,只需要通过目标接口交互。
- 符合开闭原则:可以新增适配器类而不需要修改现有系统。
缺点:
- 代码复杂度增加:引入额外的类和对象,增加系统理解难度。
- 可能影响性能:多一层间接调用会有微小开销,通常可忽略不计。
- 类适配器受语言支持限制:如果采用类适配器,可能必须依赖具体类的继承,不够灵活。
8. 何时使用适配器模式?
- 你想使用某个现有类,但其接口与你的需求不匹配。
- 你想创建一个可复用的类,该类需要与未来可能出现的未知类进行合作(这些未知类可能不提供兼容的接口)。
- 你需要对多个相似的类进行统一接口封装,避免为每个类都写重复的转换逻辑(可以使用一个适配器,让 Adaptee 实现公共接口或通过继承体系处理)。
9. 相关模式对比
- 桥接模式(Bridge):桥接是分离抽象与实现,两者可以独立变化;适配器则改变已有对象的接口。桥接通常在设计之初考虑,而适配器在事后整合不兼容接口。
- 装饰器模式(Decorator):装饰器不改变接口,只是增加责任;适配器则改变接口。装饰器支持递归组合,适配器通常只做一次转换。
- 外观模式(Facade):外观为子系统提供一个新的简化接口,而适配器是为已有的不兼容接口提供一个目标接口。外观通常定义一个新接口,适配器则重用已有接口。
10. 总结
适配器模式是你在面对“接口不兼容”时的首选工具。它通过引入一个中间层,在不修改原有代码的前提下,让新旧组件和谐共存。掌握适配器模式,你就能像摆弄电源转换插头一样,轻松连接任何看似“不搭”的系统模块。
记住关键词:转换、包装、复用。
本文为你提供了适配器模式的完整入门知识,包括概念、结构、代码实现和应用场景。现在你就可以尝试在项目中识别那些需要“转换接口”的地方,并用适配器来优雅地解决问题。