C++设计模式-适配器模式 原创 设计模式 2021年10月19日 12:57 夏至未至 1160 当前内容 7358 字,在路上,马上到,马上到 ### 目录 [TOC] ### 适配器模式介绍 #### 什么是适配器模式 适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。 #### 为何使用适配器模式 主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。 #### 如何实现适配器模式 ##### 实现方式 适配器模式有两种实现方式:`类适配器`和`对象适配器`。其中,`类适配器使用继承关系来实现`,`对象适配器使用组合关系来实现`。 ##### 方式选择 两种实现如何选择。以下可做参考: 判断的标准主要有两个,一个是 Adaptee 接口的个数,另一个是 Adaptee 和 ITarget 的契合程度。 1. 如果 Adaptee 接口并不多,那两种实现方式都可以。 2. 如果 Adaptee 接口很多,而且 Adaptee 和 ITarget 接口定义大部分都相同,那推荐使用类适配器,因为 Adaptor 复用父类 Adaptee 的接口,比起对象适配器的实现方式,Adaptor 的代码量要少一些。 3. 如果 Adaptee 接口很多,而且 Adaptee 和 ITarget 接口定义大部分都不相同,那推荐使用对象适配器,因为组合结构相对于继承更加灵活。 ### 模式注意点 适配器继承或依赖已有的对象,实现想要的目标接口。 ### 应用场景 #### 生活中场景 读卡器、电源适配器等各种转接头 #### 软件中场景 JAVA 中的 jdbc ### 如何使用适配器模式 #### 封装有缺陷的接口设计 外部系统在接口设计方面有缺陷,引入之后会影响到自身代码,为了隔离设计上的缺陷可以使用适配器模式抽象出更好的接口设计 #### 统一多个类的接口设计 某个功能的实现依赖多个外部系统(或者说类)。通过适配器模式,将它们的接口适配为统一的接口定义,然后我们就可以使用多态的特性来复用代码逻辑。比如统一多款第三方敏感词过滤系统的接口。 #### 替换依赖的外部系统 当我们把项目中依赖的一个外部系统替换为另一个外部系统的时候,利用适配器模式,可以减少对代码的改动。 #### 兼容老版本接口 在做版本升级的时候,对于一些要废弃的接口,不直接将其删除,而是暂时保留,并且标注为 deprecated,并在内部委托为新的接口实现。 #### 适配不同格式的数据 还可以用在不同格式的数据之间的适配。比如,把收集的不同存储格式的数据,统一为相同的格式,以方便存储和使用。 ### 模式特点 #### 优点 1. 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。 2. 增加了类的透明性和复用性,对于客户端类而言是透明的,同一个适配者类可以在多个不同的系统中复用。 3. 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。 #### 缺点 1. 对编程语言的限制,由于某些语言不支持多继承,一次最多只能适配一个适配者类,比如Java不支持多重继承,不能同时适配多个适配者类; 2. 过多地使用适配器,会让系统非常零乱,可读性变差不易整体进行把握,比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现 ### 模式角色类 - Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。 - Adapter(适配器类): 适配器类是适配器模式的核心,可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。 - Adaptee(适配者类): 适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码只有接口。 ### 示例代码 - 类适配器:FilterAdapter_A,FilterAdapter_B - 对象适配器:ObjectAdapter_A,ObjectAdapter_B #### 上机代码 #include //- Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。 //- Adapter(适配器类): 适配器类是适配器模式的核心,可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。 //- Adaptee(适配者类): 适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码只有接口。 // 目标抽象类 class FilterTarget { public: virtual ~FilterTarget() = default; // 最终适配成的统一目标接口 virtual void filter(std::string text) = 0; protected: FilterTarget() = default; }; // 适配者类(是现实已经存在的接口,包含了客户希望使用的业务方法) // 被适配的对象 class FilterAdaptee_A { public: FilterAdaptee_A() { std::cout << "需要被适配的类A产生" << std::endl; type = "FilterAdaptee_A"; } ~FilterAdaptee_A() { std::cout << "需要被适配的类A销毁" << std::endl; } void adapteeFilter(const char* text) { std::cout << "过滤器为:" << type << std::endl; std::cout << "过滤内容为:" << text << std::endl; } private: std::string type; }; class FilterAdaptee_B { public: FilterAdaptee_B() { std::cout << "需要被适配的类B产生" << std::endl; type = "FilterAdaptee_B"; } ~FilterAdaptee_B() { std::cout << "需要被适配的类B销毁" << std::endl; } void adapteeFilter(const std::string& text, const std::string& mask) { std::cout << "过滤器为:" << type << std::endl; std::cout << "过滤内容为:" << text << std::endl; std::cout << "过滤mask为:" << mask << std::endl; } private: std::string type; }; // 类适配器(中间人,用于适配待适配对象) // 适配 FilterAdaptee_A class FilterAdapter_A : public FilterTarget, private FilterAdaptee_A { public: FilterAdapter_A() { std::cout << "类适配器A产生" << std::endl; } ~FilterAdapter_A() override { std::cout << "类适配器A销毁" << std::endl; } // 适配成统一接口 void filter(const std::string text) override { const char* temp = text.c_str(); adapteeFilter(temp); } }; // 适配 FilterAdaptee_B class FilterAdapter_B : public FilterTarget, private FilterAdaptee_B { public: FilterAdapter_B() { std::cout << "类适配器B产生" << std::endl; mask = "MASK_CLASS"; } ~FilterAdapter_B() override { std::cout << "类适配器B销毁" << std::endl; } // 适配成统一接口 void filter(const std::string text) override { adapteeFilter(text, mask); } private: std::string mask; }; // 对象适配器 class ObjectAdapter_A : public FilterTarget { public: ObjectAdapter_A() { std::cout << "对象适配器A产生" << std::endl; } ~ObjectAdapter_A() override { std::cout << "对象适配器A销毁" << std::endl; } void filter(const std::string text) override { const char* temp = text.c_str(); filterAdapteeA.adapteeFilter(temp); } private: FilterAdaptee_A filterAdapteeA; }; class ObjectAdapter_B : public FilterTarget { public: ObjectAdapter_B() { std::cout << "对象适配器B产生" << std::endl; mask = "MASK_OBJECT"; } ~ObjectAdapter_B() override { std::cout << "对象适配器B销毁" << std::endl; } void filter(const std::string text) override { filterAdapteeB.adapteeFilter(text, mask); } private: FilterAdaptee_B filterAdapteeB; std::string mask; }; // 测试 int main() { std::cout << "网站:https://www.codecomeon.com/" << std::endl; std::cout << std::endl; // 类适配器演示 std::cout << "========类适配器演示========" << std::endl; FilterTarget* filterA = new FilterAdapter_A(); FilterTarget* filterB = new FilterAdapter_B(); // 以上AB两个类中不同接口,经过适配后,成为统一接口 filter filterA->filter("我是 FilterAdaptee_A 中方法"); filterB->filter("我是 FilterAdaptee_B 中方法"); std::cout << std::endl; // 对象适配器演示 std::cout << "========对象适配器演示========" << std::endl; FilterTarget* filterAA = new ObjectAdapter_A(); FilterTarget* filterBB = new ObjectAdapter_B(); // 以上AB两个类中不同接口,经过适配后,成为统一接口 filter filterAA->filter("我是 FilterAdaptee_A 中方法"); filterBB->filter("我是 FilterAdaptee_B 中方法"); std::cout << std::endl; delete filterAA; delete filterBB; return 0; } #### 执行输出 网站:https://www.codecomeon.com/ ========类适配器演示======== 需要被适配的类A产生 类适配器A产生 需要被适配的类B产生 类适配器B产生 过滤器为:FilterAdaptee_A 过滤内容为:我是 FilterAdaptee_A 中方法 过滤器为:FilterAdaptee_B 过滤内容为:我是 FilterAdaptee_B 中方法 过滤mask为:MASK_CLASS ========对象适配器演示======== 需要被适配的类A产生 对象适配器A产生 需要被适配的类B产生 对象适配器B产生 过滤器为:FilterAdaptee_A 过滤内容为:我是 FilterAdaptee_A 中方法 过滤器为:FilterAdaptee_B 过滤内容为:我是 FilterAdaptee_B 中方法 过滤mask为:MASK_OBJECT 对象适配器A销毁 需要被适配的类A销毁 对象适配器B销毁 需要被适配的类B销毁 E:\DesignPatterns\DesignPatterns\Debug\DesignPatterns.exe (进程 85528)已退出,代码为 0。 按任意键关闭此窗口. . . 本文标题: C++设计模式-适配器模式 本文作者: 夏至未至 发布时间: 2021年10月19日 12:57 最近更新: 2022年2月9日 14:44 原文链接: 许可协议: 署名-非商业性-禁止演绎 4.0 国际(CC BY-NC-ND 4.0) 请按协议转载并保留原文链接及作者 设计模式(25) 上一个 C++设计模式-桥接模式 下一个 C++设计模式-建造者模式 当前文章评论暂未开放,请移步至留言处留言。