当前位置: 首页 > news >正文

完整教程:C++设计模式之结构型模式:适配器模式(Adapter)

适配器模式(Adapter)是结构型设计模式的一种,它的核心作用是将一个类的接口转换成客户端期望的另一个接口,使原本因接口不兼容而无法协作的类能够一起工作。这种模式类似于现实生活中的“转换器”(如电源适配器、USB转接头)。

一、核心角色与设计思想

适配器模式通过以下3个核心角色实现接口转换:

角色名称核心职责
目标接口(Target)客户端期望的接口,定义了客户端可以使用的方法。
适配者(Adaptee)已存在的、但接口与目标接口不兼容的类(需要被适配的类)。
适配器(Adapter)实现目标接口,并内部包含适配者的实例,通过转换调用适配者的方法,完成接口适配。

核心思想:不修改现有类(适配者)和客户端代码,通过引入适配器类,将适配者的接口转换为目标接口,实现两者的兼容。

二、实现方式

适配器模式有两种主要实现方式,根据适配器与适配者的关系不同区分:

1. 类适配器(继承实现)

适配器通过继承适配者类实现目标接口,将适配者的方法转换为目标接口方法。

#include <iostream>#include <string>// 1. 目标接口(客户端期望的接口)class Target {public:virtual void request(const std::string& data) const = 0;virtual ~Target() = default;};// 2. 适配者(已存在的、接口不兼容的类)class Adaptee {public:// 适配者的方法与目标接口方法名/参数不同void specificRequest(const std::string& data, int format) const {std::cout << "适配者处理数据:" << data<< "(格式:" << format << ")" << std::endl;}};// 3. 类适配器(继承适配者 + 实现目标接口)class ClassAdapter : public Target, private Adaptee {public:// 实现目标接口方法,内部调用适配者的方法void request(const std::string& data) const override {// 转换参数并调用适配者的specificRequestspecificRequest(data, 1); // 假设格式1是客户端需要的格式}};// 客户端代码:只依赖目标接口void clientCode(const Target* target) {target->request("测试数据");}int main() {std::cout << "直接使用适配者(接口不兼容,无法调用)" << std::endl;// Adaptee adaptee;// adaptee.request("数据"); // 编译错误:Adaptee没有request方法std::cout << "\n使用类适配器:" << std::endl;Target* adapter = new ClassAdapter();clientCode(adapter); // 客户端通过适配器调用适配者delete adapter;return 0;}
2. 对象适配器(组合实现)

适配器通过实现目标接口组合适配者对象(而非继承),完成接口转换。这是更常用的实现方式,符合“组合优于继承”原则。

#include <iostream>#include <string>// 1. 目标接口(与类适配器相同)class Target {public:virtual void request(const std::string& data) const = 0;virtual ~Target() = default;};// 2. 适配者(与类适配器相同)class Adaptee {public:void specificRequest(const std::string& data, int format) const {std::cout << "适配者处理数据:" << data<< "(格式:" << format << ")" << std::endl;}};// 3. 对象适配器(实现目标接口 + 组合适配者对象)class ObjectAdapter : public Target {private:Adaptee* adaptee; // 持有适配者对象的指针(组合关系)public:// 构造函数接收适配者对象ObjectAdapter(Adaptee* a) : adaptee(a) {}// 实现目标接口方法,通过适配者对象调用其方法void request(const std::string& data) const override {if (adaptee) {adaptee->specificRequest(data, 2); // 转换参数}}};// 客户端代码(与类适配器相同)void clientCode(const Target* target) {target->request("测试数据");}int main() {std::cout << "使用对象适配器:" << std::endl;Adaptee* adaptee = new Adaptee();Target* adapter = new ObjectAdapter(adaptee);clientCode(adapter); // 客户端通过适配器调用适配者// 注意释放顺序:先释放适配器,再释放适配者delete adapter;delete adaptee;return 0;}

三、代码解析

  1. 目标接口(Target):定义客户端需要的方法request(const std::string&),是客户端与适配器交互的标准。

  2. 适配者(Adaptee):存在一个specificRequest方法,但参数(多了int format)和名称与目标接口不兼容,无法被客户端直接调用。

  3. 适配器的作用

    • 类适配器通过继承Adaptee和实现Target,在request中调用父类的specificRequest,完成参数转换。
    • 对象适配器通过持有Adaptee指针,在request中调用其specificRequest,同样完成转换。
  4. 客户端:仅依赖Target接口,无需知道Adaptee的存在,实现了解耦。

四、两种实现方式的对比

对比维度类适配器(继承)对象适配器(组合)
实现方式继承适配者类,实现目标接口实现目标接口,持有适配者对象
灵活性只能适配特定适配者,无法适配其子类可适配适配者及其子类,更灵活
代码耦合与适配者类强耦合(继承关系)与适配者弱耦合(组合关系)
方法重写可重写适配者的方法无法重写适配者的方法(需通过其他方式)
适用场景适配者类稳定,且不需要适配其子类适配者可能变化,或需要适配多种子类

推荐优先使用对象适配器,因为组合比继承更灵活,且符合面向对象设计原则。

五、适用场景与优势

适用场景
  1. 集成 legacy 代码:当需要使用旧系统中的类,但它的接口与新系统不兼容时(如旧数据库驱动适配新ORM框架)。
  2. 复用第三方库:第三方库的接口不符合项目规范,通过适配器转换后再使用。
  3. 统一接口风格:将多个功能相似但接口不同的类,通过适配器统一为相同接口(如不同日志库统一为项目的日志接口)。
核心优势
  1. 兼容性:解决接口不兼容问题,使原本无法协作的类可以一起工作。
  2. 复用性:无需修改现有类(适配者)即可复用,保护现有代码。
  3. 透明性:客户端只需与目标接口交互,无需知道适配者的存在。
  4. 灵活性:通过更换不同适配器,可在不修改客户端的情况下切换适配者。

六、与其他模式的区别

模式核心差异点
适配器转换现有接口,解决“接口不兼容”问题,不改变原有功能。
装饰器不改变接口,为对象增加新功能,强调功能扩展。
外观(Facade)为复杂系统提供简化接口,关注“简化使用”,不涉及接口转换。
桥接(Bridge)分离抽象与实现,使两者可独立变化,解决“多维度变化”问题。

七、实践建议

  1. 优先对象适配器:除非必须继承适配者(如需要重写其方法),否则优先使用组合实现的对象适配器。
  2. 明确目标接口:设计清晰的Target接口,确保它能满足客户端需求。
  3. 适配多个适配者:一个适配器可适配多个相关的适配者(如同时适配数据读取和数据解析类)。
  4. 避免过度使用:不要为了适配而适配,若能直接修改接口,应优先修改而非引入适配器。

适配器模式是系统集成和代码复用的重要工具,尤其在维护 legacy 系统或整合第三方库时能显著降低耦合。其核心价值在于“在不破坏现有代码的前提下,实现接口兼容”,是结构型模式中解决“接口不匹配”问题的最佳方案。

http://www.hskmm.com/?act=detail&tid=21980

相关文章:

  • 网页访问速度很慢,远程仓库调用很慢
  • 深入解析:【项目】Vision Master OpenCV 3.0 版本(预)发行说明
  • 2025木方厂家权威推荐榜:实力工厂与优质供应之选
  • 10 月做题记录
  • LoRa/LoRaWAN技术手册
  • 便宜的 VPS
  • 2025南通宠物医院权威推荐榜:专业诊疗与暖心服务口碑之选
  • 【JavaScript 性能优化实战】第六篇:性能监控与自动化优化 - 指南
  • linux 系统cshrc 资料
  • 2025 年西安品质楼盘住宅推荐排行榜权威发布,精选优质楼盘推荐
  • 某商业银行项目管理建设演进报告 - 指南
  • 题解:P14073 [GESP202509 五级] 数字选取
  • 2025西安新房住宅推荐排行榜发布,房屋品质、周边配套、交通便利性多维度选择指南!
  • 华为造车“内战”!徐直军下场做“启境”,会比余承东五界更强?
  • 余承东的新职位传递了华为重大信息
  • 张雪峰的事儿,大有文章
  • 词(持续更新)语言的边界就是
  • 财务分析怎么做 - 智慧园区
  • Maven的安装与配置
  • 2025包装机厂家推荐榜单出炉:拉伸膜真空包装机,全自动真空包装机,滚动式真空包装机,食品真空包装机,气调包装机公司推荐!
  • 2025年真空机厂家推荐榜:平台式真空封口机,拉伸膜真空覆膜机,全自动拉伸膜真空包装机,滚动连续式真空包装机,双面拉伸真空包装机公司实力甄选指南
  • 【半导体器件 | 笔记】金属氧化物半导体场效应晶体管(MOSFET)
  • 元人文AI场域:在有限与无限的纠缠中走向智慧文明
  • 【半导体器件 | 笔记】双极晶体管(BJT)
  • Luogu P3863 序列 题解 [ 紫 ] [ 分块 ] [ 扫描线 ]
  • [HCTF 2018]WarmUp
  • Day2:Linux文件目录移到拷贝与vim编辑器使用指南
  • 【半导体物理 | 笔记】第八章 半导体表面与MIS结构
  • 【半导体物理 | 笔记】第七章 金属和半导体的接触
  • 【半导体物理 | 笔记】第四章 半导体的导电性