深入设计模式之「适配器模式」:如何让“插头不兼容”的系统顺畅协作?

一、什么是适配器模式(Adapter Pattern)?

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

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


二、为什么要使用适配器模式?

在实际开发中,我们常遇到老接口不能直接用,但又不能直接改源码的情况:

  • 使用的第三方库接口和自己系统不兼容

  • 老系统接口无法满足新需求,但又不能破坏原有逻辑

  • 两个模块由不同团队设计,接口对不上

此时,修改代码代价太高或不可行,最好的办法是加一层“翻译器” → 这正是适配器的职责。


✅ 举例:不同国家的插头

出国旅行时,你的手机充电器是扁头插头 🇨🇳,但酒店插座是圆孔 🇪🇺,怎么办?

你不会砸掉墙上的插座重装,也不会改造你的充电器 ——

✅ 你会用一个“插头适配器”把它们连接起来。

这就是适配器模式


三、适配器模式适用场景

触发场景

原因或需求

系统之间接口不同,无法直接协作

第三方库/老模块/其他团队产出的类接口不一致

不允许修改原始类代码

原类可能已封装、已部署、已在多个地方使用,不可直接更改

希望在不破坏现有代码的基础上,兼容新旧接口

新系统上线,需要兼容老版本接口或数据模型

希望复用现有功能,但需要对接统一标准

统一平台标准接入,不希望重写已有逻辑


四、Java 实战:对象适配器模式(基于组合)

✅ 背景设定:客户端期望的是 Target 接口,但现成类是 Adaptee

// 客户端期望的接口
public interface Target {
    void request();
}
// 现成类(第三方、老代码)
public class Adaptee {
    public void specificRequest() {
        System.out.println("来自 Adaptee 的特殊请求");
    }
}

✅ 适配器类:桥接 Target 和 Adaptee

// 适配器:将 Adaptee 接口“翻译”为 Target 接口
public class Adapter implements Target {
    private Adaptee adaptee;
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    @Override
    public void request() {
        // 转调 Adaptee 的方法
        adaptee.specificRequest();
    }
}

📦 使用方式:

Target target = new Adapter(new Adaptee());
target.request(); // 输出:来自 Adaptee 的特殊请求

✅ 场景说明

假设你原本的系统接口是 Target,但你现在想接入某个 SDK(它只有 specificRequest() 方法),无法直接使用。

适配器封装了差异,客户端依然调用原始方式 request(),无感知。


五、类适配器模式(基于继承)

Java 中支持单继承,因此类适配器只能在单继承情况下使用

public class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest(); // 直接调用继承来的方法
    }
}

📦 使用方式:

Target t = new ClassAdapter(); t.request();

✅ 类适配器 vs 对象适配器

对比维度

类适配器(继承)

对象适配器(组合)

灵活性

不如组合灵活(受限于单继承)

高,可适配多个对象

可扩展性

不易扩展其他适配逻辑

可灵活添加桥接逻辑

适用场景

简单适配,结构固定

更通用,推荐使用对象适配器 ✅


六、缺点与触发场景

缺点

场景说明

引入适配器增加系统复杂度

若接口种类多,适配器数量可能爆炸,代码维护成本升高

运行时可能隐藏错误

不匹配时逻辑可能被吞掉,运行时报错而非编译时报错

破坏系统一致性

过多适配器会导致系统风格不统一,新旧接口混用

只能适配现有接口

无法处理类内部行为差异或副作用,如状态不一致


🔍 场景举例(问题触发)

1. 第三方支付 SDK 接入

原系统调用方式:

paymentService.pay(amount);

新接入的 SDK 只有:

sdk.processTransaction(amount, currency, key);

你不能改系统代码,只能适配:

public class SdkPaymentAdapter implements PaymentService {
    private NewPaymentSDK sdk;
    public void pay(double amount) {
        sdk.processTransaction(amount, "CNY", "api-key");
    }
}

2. 接口迁移但必须兼容老版本

老代码中:

public interface Logger {
    void log(String message);
}

新系统使用:

public class AdvancedLogger {
    public void write(String level, String message) { ... }
}

使用适配器保持兼容:

public class LoggerAdapter implements Logger {
    private AdvancedLogger advLogger = new AdvancedLogger();
    public void log(String message) {
        advLogger.write("INFO", message);
    }
}

七、适配器模式 VS 装饰器/桥接/代理模式

模式

作用焦点

是否改变接口

是否新增行为

典型用途

适配器

接口转换

兼容旧系统/对接第三方接口

装饰器

增强原有功能

动态功能扩展,增强行为

桥接模式

解耦抽象与实现

多维度变化、避免类爆炸

代理模式

控制访问、延迟执行、安全控制等

✅(控制行为)

远程调用、缓存、安全等场景


八、总结

适配器模式是处理接口不兼容但不能改原类的终极方案。

它优雅地隔离了“调用者”和“被调用者”之间的差异,避免侵入式修改,有效提升系统兼容性和灵活性。

但请注意,适配器滥用会让系统结构臃肿、逻辑分散,因此适当封装、统一命名、归档适配器十分重要。

下一篇将带你深入讲解「桥接模式」的核心思想与进阶用法 👨‍🏫

如需Java面试题资料,可关注公众号:小健学Java,回复“面试”即可获得!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小健学 Java

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值