设计模式每日硬核训练 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):动态增强对象功能,不侵入原类,组合胜继承。

相关推荐
铁弹神侯6 分钟前
Maven相关名词及相关配置
java·maven
会飞的皮卡丘EI20 分钟前
关于Blade框架对数字类型的null值转为-1问题
java·spring boot
雷渊22 分钟前
如何保证数据库和Es的数据一致性?
java·后端·面试
fjkxyl23 分钟前
Spring的启动流程
java·后端·spring
极客先躯25 分钟前
高级java每日一道面试题-2025年4月06日-微服务篇[Nacos篇]-如何诊断和解决Nacos中的常见问题?
java·开发语言·微服务
东锋1.333 分钟前
Spring AI 发布了它的 1.0.0 版本的第七个里程碑(M7)
java·人工智能·spring
liwulin05061 小时前
【JAVAFX】自定义FXML 文件存放的位置以及使用
java
2401_890665861 小时前
免费送源码:Java+ssm+MySQL 基于PHP在线考试系统的设计与实现 计算机毕业设计原创定制
java·hadoop·spring boot·python·mysql·spring cloud·php
胎粉仔1 小时前
Swift —— delegate 设计模式
开发语言·设计模式·swift
逸风尊者1 小时前
开发可掌握的知识:基于事件驱动实现状态机
java