设计模式每日硬核训练 Day 11:适配器模式(Adapter Pattern)完整讲解与实战应用

🔄 回顾 Day 10:模板方法模式小结

在 Day 10 中,我们学习了模板方法模式:

  • 它用于定义流程的"骨架",将固定步骤放在父类,具体实现交给子类完成。
  • 实现了"统一流程 + 差异化行为"的复用范式。

而今天,我们来学习一个更具桥梁意义的结构型模式------适配器模式(Adapter Pattern)


一、适配器模式的核心动机

✅ 什么是适配器?

适配器模式用于:

将一个已有接口转换为客户所期望的另一个接口,使原本由于接口不兼容而不能一起工作的类能协同工作。

简单理解:"旧接口 + 新系统 = 用适配器来衔接"

📦 应用动机:

  • 第三方库或老代码接口不可更改
  • 新系统定义了统一接口,老模块不兼容
  • 不希望大规模重构,只想局部"桥接"

二、典型结构图(UML)

复制代码
+----------------+        +---------------------+
| Target         |<-------| Adapter             |
+----------------+        +---------------------+
| +request()     |        | +request()          |
+----------------+        | - adaptee: Adaptee  |
                          | +Adapter(adaptee)   |
                          +---------------------+
                                     |
                                     |
                              +--------------+
                              | Adaptee       |
                              +--------------+
                              | +specific()   |
                              +--------------+

✅ 角色解释:

角色 职责
Target 客户希望使用的接口
Adaptee 现有功能类,接口不兼容
Adapter 适配器,将 Target 接口转换为对 Adaptee 的调用

三、分类:类适配器 vs 对象适配器

方式 特点 实现方式
类适配器 通过继承实现,适用于单继承结构 class Adapter : public Adaptee, public Target
对象适配器 通过组合实现,更灵活、推荐使用 Adapter 包含 Adaptee 指针或引用

四、C++ 实现:日志系统适配不同输出端

🎯 场景背景

系统原本只支持写入 std::ofstream 文件,现在希望支持第三方 LegacyLogger 类(它只能使用 writeLegacy() 方法输出)。为了统一日志接口,我们采用适配器模式。

✅ Target 接口(期望的日志接口)

cpp 复制代码
class ILogger {
public:
    virtual void log(const std::string& message) = 0;
    virtual ~ILogger() = default;
};

✅ Adaptee(第三方或老接口)

cpp 复制代码
class LegacyLogger {
public:
    void writeLegacy(const std::string& text) {
        std::cout << "[Legacy] " << text << std::endl;
    }
};

✅ Adapter(桥接类)

cpp 复制代码
class LoggerAdapter : public ILogger {
private:
    LegacyLogger* legacy_;
public:
    LoggerAdapter(LegacyLogger* legacy) : legacy_(legacy) {}

    void log(const std::string& message) override {
        legacy_->writeLegacy(message);
    }
};

✅ Client 使用

cpp 复制代码
void runLogger(ILogger* logger) {
    logger->log("程序已启动");
}

int main() {
    LegacyLogger legacy;
    LoggerAdapter adapter(&legacy);

    runLogger(&adapter);  // 无需修改 runLogger,实现日志模块适配
    return 0;
}

五、实战场景举例(工业开发常见)

应用场景 适配器用途说明
Qt5 与 Qt6 事件兼容 Qt6 接口变化较大,编写 Qt5 兼容适配层
驱动程序接口迁移 新版驱动框架要求统一接口,旧驱动通过适配器连接
通信协议切换 适配器桥接老协议栈与新通信接口
Web 服务封装 使用适配器将第三方 SDK 接口封装为内部统一 API 接口
配置加载兼容 旧项目使用 INI,新项目使用 JSON,使用适配器统一配置读取方式

六、与桥接、装饰器、策略的对比

模式 意图 典型使用时机
Adapter 接口转换,兼容旧系统 连接新旧系统,替换不可更改类
Bridge 分离接口与实现(双维度变化) 需要独立扩展实现与接口两个维度
Decorator 增强功能 不改原始类而增加功能
Strategy 算法封装、运行时切换 多算法切换

七、面试回答模板

"我们在设备接入框架中使用适配器模式非常频繁,比如将老式协议数据转换为平台统一数据格式,或者在引入第三方模块时用适配器封装它的日志接口,统一为我们的 ILogger 接口,便于替换与测试。适配器帮助我们降低耦合、提升兼容性。"

✅ 加分点:强调对象适配器 vs 类适配器的选择理由。


八、口诀记忆

"老接口,新系统,中间加桥梁;不改老代码,外部巧适配。"


九、明日预告:Day 12

装饰器模式(Decorator Pattern):动态增强对象功能,不侵入原类,组合胜继承。

相关推荐
程序员清风27 分钟前
阿里二面:Kafka 消费者消费消息慢(10 多分钟),会对 Kafka 有什么影响?
java·后端·面试
幼稚园的山代王28 分钟前
Prompt Enginering(提示工程)先进技术
java·人工智能·ai·chatgpt·langchain·prompt
周某某~37 分钟前
二.单例模式‌
java·单例模式·设计模式
摸鱼仙人~39 分钟前
深入理解Java单例模式:确保类只有一个实例
java·javascript·单例模式
十五年专注C++开发1 小时前
设计模式之单例模式(二): 心得体会
开发语言·c++·单例模式·设计模式
hstar95271 小时前
三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
java·后端·spring·设计模式·架构·mvc
pengyu1 小时前
【Java设计原则与模式之系统化精讲:壹】 | 编程世界的道与术(实战指导篇)
java·后端·设计模式
日月星辰Ace1 小时前
JVM 垃圾回收简介
java
掉头发的王富贵1 小时前
Arthas神器入门:动态调试Java应用,轻松搞定生产环境Bug!
java·后端·debug
Java陈序员2 小时前
再见 Navicat!一款开源的 Web 数据库管理工具!
java·react.js·docker