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

相关推荐
AI人工智能+电脑小能手8 分钟前
【大白话说Java面试题 第94题】【Mysql篇】第24题:什么是单路排序?什么是双路排序??
java·开发语言·数据库·mysql·面试·排序算法
我是一颗柠檬9 分钟前
【Java项目技术亮点】多级缓存一致性方案:Canal+MQ实现数据库与缓存的最终一致
java·数据库·spring·缓存·kafka·rocketmq
于先生吖9 分钟前
Java分账体系设计,网约车行程计费与到店线下结账一体化后端开发实战
java·开发语言
Solis程序员10 分钟前
拿捏登录安全:RS256 + 双令牌,把非法请求拦在 Redis 白名单门外
java·安全·缓存·面试·bootstrap·html
thisiszdy12 分钟前
<C++&C#> lambda表达式
java·c++·c#
咖啡八杯13 分钟前
GoF设计模式——外观模式
java·设计模式·外观模式
郝学胜-神的一滴13 分钟前
系统设计 014:缓存深度实战:如何用 Cache 优雅优化数据库读写?
java·数据库·python·缓存·oracle·php·软件构建
xuankuxiaoyao15 分钟前
阶段案例——后台管理系统
java·linux·前端
摇滚侠18 分钟前
JavaWeb 全套教程 Tomcat 53-62
java·tomcat
隔窗听雨眠28 分钟前
ORM框架选型指南:MyBatis与Hibernate的全面对比
java·开发语言·数据库