如何让 iPhone 用上 Type-C 充电器?适配器模式详解

在软件开发中,我们经常面临一个尴尬的局面:

你接手了一个 10 年前的老系统,里面有一个核心类 OldService,它的方法叫 doSomethingOld()

现在公司推行新架构,所有服务必须实现一个新的接口 NewInterface,方法叫 process()

冲突来了

  • 你不能改老代码(没人敢动,怕崩)。
  • 你必须用新接口。
  • 这两个接口长得完全不一样。

怎么办?把老代码重写一遍?那估计你也得离职了。

最优雅的办法是:加一个适配器。就像你出国旅游,买个插头转换器一样。


🔌 一、技术分析:偷天换日

适配器模式的核心思想是:将一个类的接口,转换成客户期望的另一个接口。

它让原本因为接口不兼容而不能在一起工作的类,可以协同工作。

1. 核心角色

  • Target (目标接口) : 客户期待的接口(比如 Type-C 接口)。
  • Adaptee (被适配者) : 那个需要被兼容的老家伙(比如 Lightning 接口)。
  • Adapter (适配器): 那个转换头。它实现了 Target 接口,并在内部持有一个 Adaptee 的引用。

2. 两种实现方式

  1. 类适配器 (Class Adapter) : 通过继承来实现。
  • class Adapter extends OldService implements NewInterface
  • 缺点: Java 是单继承,这占用了继承坑位,不太灵活。
  1. 对象适配器 (Object Adapter) : 通过组合 来实现。(推荐)
  • class Adapter implements NewInterface { private OldService old; ... }
  • 优点: 更加灵活,符合"组合优于继承"原则。

✈️ 二、故事场景:出国旅游的"转换插头"

为了搞懂适配器,我们将 代码对接 比作 出国充电

1. 场景设定

  • 你的电脑 (Client) : 是一台中国产的联想,插头是 三孔扁头
  • 酒店插座 (Adaptee) : 是一家美国酒店,墙上的插孔是 两孔圆头
  • 冲突: 电脑插不进去,没法充电。

2. 解决方案 (Adapter)

你不会因为插不进去就把酒店墙砸了(重构老系统),也不会把电脑插头剪了(修改客户端)。

你会买一个 "中美转换头"

  • 转换头的外观 (Target) : 它是 两孔圆头 的(能插进墙里)。
  • 转换头的屁股 (Adaptee) : 它有个 三孔扁头 的插口(能接你的电脑)。
  • 内部逻辑: 转换头把墙里的电引出来,传给你的电脑。

3. 代码演示

java 复制代码
// 1. 目标接口:新系统只认 Type-C
interface TypeC {
    void connectTypeC();
}

// 2. 被适配者:老手机是 Lightning 接口
class IPhone {
    public void connectLightning() {
        System.out.println("正在使用 Lightning 充电...");
    }
}

// 3. 适配器:把 Lightning 伪装成 Type-C
class LightningAdapter implements TypeC {
    private IPhone iPhone; // 持有老对象的引用 (组合)

    public LightningAdapter(IPhone iPhone) {
        this.iPhone = iPhone;
    }

    @Override
    public void connectTypeC() {
        // 偷梁换柱:表面调 TypeC,实际调 Lightning
        System.out.println("适配器开始工作:转接中...");
        iPhone.connectLightning();
    }
}

// 4. 使用
public class User {
    public static void main(String[] args) {
        IPhone oldPhone = new IPhone();
        // 这里的 adapter 看起来像个 TypeC,其实内部包着 Lightning
        TypeC adapter = new LightningAdapter(oldPhone);
        
        adapter.connectTypeC(); 
    }
}

🚀 三、实战:Spring MVC 的"万能遥控器"

你可能没手写过适配器,但你天天都在用。

1. Spring MVC 的 HandlerAdapter

在 Spring MVC 中,你写的 Controller 有很多种写法:

  • @RequestMapping (最常用的)
  • 实现 Controller 接口 (古老写法)
  • 实现 HttpRequestHandler 接口 (处理静态资源)

DispatcherServlet (核心控制器) 很头大:"你们这帮 Controller 长得都不一样,我怎么调用你们?"

于是 Spring 设计了 HandlerAdapter

  • RequestMappingHandlerAdapter: 专门适配注解写的 Controller。
  • SimpleControllerHandlerAdapter: 专门适配实现了接口的 Controller。

DispatcherServlet 只需要调用 adapter.handle(),适配器内部会去调用你那个千奇百怪的 Controller 方法。

2. 日志门面 (SLF4J)

你项目中可能同时用了 Log4j、Logback、JDK Logging。

SLF4J 就是一个巨大的适配器集合。它让你用统一的代码 log.info(),底层自动适配到各种不同的日志实现上。


🥊 四、易混淆模式对比

这三个模式结构都是 "Wrapper" (包装器),但意图完全不同:

模式 意图 形象比喻 接口变化
装饰器 (Decorator) 增强功能 钢铁侠战衣 接口不变
代理 (Proxy) 控制访问 明星经纪人 接口不变
适配器 (Adapter) 兼容接口 电源转换头 接口变了
  • 装饰器: 我还是我,但我变强了。
  • 代理: 你以为是我,其实是我的替身。
  • 适配器: 我原本不是这个,但我伪装成了这个。

🎯 五、总结:没有什么是不兼容的

适配器模式的本质是 "妥协"

当新旧世界发生冲突,而我们又无力改变世界(老代码)时,适配器就是那座桥梁。它让两个原本老死不相往来的类,能够握手言和。

相关推荐
代码改善世界2 小时前
C语言项目实战:学生成绩管理系统(支持登录注册、随机考试、分数区间统计)
c语言·网络·课程设计
『往事』&白驹过隙;5 小时前
浅谈PC开发中的设计模式搬迁到ARM开发
linux·c语言·arm开发·设计模式·iot
Kurbaneli6 小时前
C语言过时了吗?2025年仍不可替代
c语言·开发语言
智者知已应修善业7 小时前
【PAT乙级真题解惑1012数字分类】2025-3-29
c语言·c++·经验分享·笔记·算法
v_for_van8 小时前
力扣刷题记录6(无算法背景,纯C语言)
c语言·算法·leetcode
爱编码的小八嘎8 小时前
第2章 认识CPU-2.3 32位微处理器(1)
c语言
BackCatK Chen9 小时前
第十五章 吃透C语言结构与数据形式:struct/union/typedef全解析
c语言·开发语言·数据结构·typedef·结构体·函数指针·联合体
『往事』&白驹过隙;9 小时前
C/C++中的格式化输出与输入snprintf&sscanf
linux·c语言·c++·笔记·学习·iot·系统调用
m0_531237179 小时前
C语言-初始化赋值,函数,变量的作用域与生命周期
c语言·开发语言