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

C++设计模式——Adapter适配器模式

一,适配器模式简介

适配器模式是一种结构型设计模式,用于将已有接口转换为调用者所期望的另一种接口。

适配器模式让特定的API接口可以适配多种场景。例如,现有一个名为"Reader()"的API接口只能解析txt格式的文件,给这个Reader()接口增加适配器以后,它可以同时支持xml、json、csv等格式的文件。

适配器是一个特殊的类,它可以扩展或者说转接一些特定API接口的功能,使得API接口可以被应用到更多对象或数据类型上。

适配器会将适配过程进行封装,从而隐藏适配的过程,只对外界提供被适配以后的API接口。

适配器在真实世界中的模拟:

1.USB转接头,实现typec接口转USB。

2.设备网关,让ipv4网络与ipv6网络互通。

适配器模式的主要组件:

1.目标接口(Target):提供给外部程序的统一接口,是外部调用者(client)期望使用的接口。

2.源接口(Adaptee):已经具备一定的功能,但是与Target不兼容的接口。它包含了client所需要的功能,但是不能被client所使用。

3.适配器(Adapter):对源接口进行适配,使得源接口可以像目标接口一样被公共调用。适配器提供了Target的接口实现,并通过继承或组合的方式调用了Adaptee的接口。

适配器模式的优点:

1.可以实现对现有组件代码的复用。

2.使得不兼容的组件之间可以成功交互。

3.降低了各种接口之间的用法差异。

4.方便集成第三方库或者API。

适配器模式与桥接模式(Bridge Pattern)的区别:

两者的用途不同,桥接模式的用途是将接口与实现分开,适配器模式的用途是修改现有接口,从而解决兼容问题。

二,适配器模式的应用场景

在开发场景中,适配器模式的应用场景有:

1.兼容相同业务下的不同接口实现。

2.兼容不同的通信方式,比如使用适配器将UDP通信转为内部的共享内存通信。

3.处理代码中不同类之间交互时的兼容问题。

在嵌入式开发场景,经常使用的Wrapper,也是一种适配器模式。Wrapper是指将传感器等硬件或者操作系统的底层API封装成一种高级接口或者类,从而提供给上层应用去调用。

Wrapper可以隐藏底层的具体实现细节,使上层应用程序可以更加方便地使用底层接口。例如,当嵌入式设备需要读写摄像头数据时,我们可以把摄像头提供的SDK封装成一个Wrapper,从而简化了调用方式。

不推荐使用适配器的场景:

1.原有接口的变动很大的时候。

2.对接口性能要求很高的时候。

3.适配器需要适配的地方过多的时候。

三,适配器代码样例

1.UML类图

Adapter类继承了Target类并重写了Target类的request接口,Adapter类实现request接口的时候调用了Adaptee类提供的specificRequest接口。

整体上,相当于Adapter类为Adaptee类的specificRequest接口做了适配。

2.代码实现

#include <iostream>
//目标接口
class Target
{
public:virtual void request() = 0;
};
//源接口
class Adaptee
{
public:void specificRequest(){std::cout << "Adaptee specific request" << std::endl;}
};
//被适配后的源接口
class Adapter : public Target
{
public:Adapter(Adaptee* adaptee) : m_adaptee(adaptee) {}void request() override{m_adaptee->specificRequest();}
private:Adaptee* m_adaptee;
};
int main()
{Adaptee* adaptee = new Adaptee();Target* target = new Adapter(adaptee);target->request();return 0;
}

运行结果: 

Adaptee specific request

四,适配器模式的分类

1.类适配器:

类适配器以类继承的方式适配不兼容的源接口。

C++语法支持继承自多个父类(钻石继承),适配器同时继承了目标接口和源接口,从而使得源接口的函数可以被目标接口所调用。

2.对象适配器:

对象适配器以对象组合的方式适配不兼容的源接口。所谓的对象组合,是指在一个对象内部调用另一个对象的成员函数。

对象适配器中包含了源接口的实例对象,对象适配器的可扩展性更好,方便加入新的功能进行适配。

五,代码实战

Demo1:  

适配了咖啡机和榨汁机的饮料机,采用对象适配器实现。

#include <iostream>
#include <functional>class  Beverage {
public:virtual void getBeverage() = 0;
};class CoffeeMaker {
public:CoffeeMaker() = default;void Brew() {std::cout << "Brewing coffee" << std::endl;}
};class JuiceMaker {
public:JuiceMaker() = default;void Squeeze() {std::cout << "Squeezeing Juice" << std::endl;}
};class Adapter : Beverage {  
private:std::function<void()> m_request;
public:Adapter(CoffeeMaker* cm){ m_request = [cm]() { cm->Brew(); };}Adapter(JuiceMaker* jm) { m_request = [jm]() { jm->Squeeze(); }; }//对外公共接口void getBeverage() { m_request(); }
};int main() {CoffeeMaker* CM= new CoffeeMaker();Adapter coffee(CM);coffee.getBeverage();JuiceMaker* JM = new JuiceMaker();Adapter juice(JM);juice.getBeverage();return 0;
}

运行结果: 

Brewing coffee
Squeezeing Juice

Demo2: 

类适配器与对象适配器代码对比

#include <iostream>//目标接口
class Target {
public:virtual void Request() = 0;
};//源接口
class Adaptee {
public:void SpecificRequest() {std::cout << "Adaptee output." << std::endl;}
};//对象适配器
class ObjectAdapter : public Target {
public://源接口的实例化ObjectAdapter(Adaptee* adaptee) : m_adaptee(adaptee) {}void Request() override {std::cout << "From ObjectAdapter: ";m_adaptee->SpecificRequest();}
private:Adaptee* m_adaptee;
};//类适配器
//钻石继承
class ClassAdapter : public Target, private Adaptee {
public:void Request() override {std::cout << "From ClassAdapter: " ;SpecificRequest();}
};int main()
{Adaptee* adaptee = new Adaptee();ObjectAdapter* adapter_1 = new ObjectAdapter(adaptee);ClassAdapter* adapter_2 = new ClassAdapter();adapter_1->Request();adapter_2->Request();return 0;
}

运行结果:

From ObjectAdapter: Adaptee output.
From ClassAdapter: Adaptee output.

六,参考阅读

https://refactoring.guru/design-patterns/adapter

https://www.geeksforgeeks.org/adapter-pattern-c-design-patterns/

相关文章:

C++设计模式——Adapter适配器模式

一&#xff0c;适配器模式简介 适配器模式是一种结构型设计模式&#xff0c;用于将已有接口转换为调用者所期望的另一种接口。 适配器模式让特定的API接口可以适配多种场景。例如&#xff0c;现有一个名为"Reader()"的API接口只能解析txt格式的文件&#xff0c;给这…...

Python文本处理利器:jieba库全解析

文章目录 Python文本处理利器&#xff1a;jieba库全解析第一部分&#xff1a;背景和功能介绍第二部分&#xff1a;库的概述第三部分&#xff1a;安装方法第四部分&#xff1a;常用库函数介绍1. 精确模式分词2. 全模式分词3. 搜索引擎模式分词4. 添加自定义词典5. 关键词提取 第…...

【C/C++】C语言如何实现类似C++的智能指针?

在C中&#xff0c;智能指针是为了自动化资源管理而引入的工具。比如std::unique_ptr和std::shared_ptr等&#xff0c;它们管理着所持有对象的生命周期&#xff0c;可以在智能指针被销毁时自动释放其所持有的资源。在C语言中&#xff0c;虽然没有直接的智能指针概念&#xff0c;…...

九大微服务监控工具详解

Prometheus Prometheus 是一个开源的系统监控、和报警工具包&#xff0c;Prometheus 被设计用来监控“微服务架构”。 主要解决&#xff1a; 监控和告警&#xff1a;Prometheus 可以对系统、和应用程序进行实时监控&#xff0c;并在出现问题时发送告警&#xff1b;数据收集和…...

java aliyun oss上传和下载工具类

java aliyun oss上传和下载工具类 依赖 <dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.8.0</version></dependency>工具类 import com.alibaba.fastjson.JSON; import c…...

P7 品牌管理

逆向生成页面 新增菜单—商品系统的品牌管理 —product/brand 在代码生成器得到的文件中&#xff0c; main-resources-src-views-modules-product brand.vue、brand-add-or-update.vue放到category.vue同级vue文件有新增、删除按钮&#xff0c;但页面未显示&#xff0c;是因…...

C语言详解(动态内存管理)1

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…...

106.网络游戏逆向分析与漏洞攻防-装备系统数据分析-在UI中显示装备与技能信息

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…...

AWS EMR Serverless

AWS概述 EMR Serverless 简介 在AWS概述一文中简单介绍过AWS EMR, 它是AWS提供的云端大数据平台。借助EMR可以设置集群以便在几分钟内使用大数据框架处理和分析数据。创建集群可参考官方文档&#xff1a;Amazon EMR 入门。但集群创建之后需要一直运行&#xff0c;用户需要管理…...

Java面试题:Redis持久化问题

Redis持久化问题 RDB (Redis Database Backup File) Redis数据快照 将内存中的所有数据都记录到磁盘中做快照 当Redis实例故障重启时,从磁盘读取快照文件恢复数据 使用 save/bgsave命令进行手动快照 save使用主进程执行RDB,对所有命令都进行阻塞 bgsave使用子进程执行R…...

【Java】解决Java报错:ClassCastException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 错误的类型转换2.2 泛型集合中的类型转换2.3 自定义类和接口转换 3. 解决方案3.1 使用 instanceof 检查类型3.2 使用泛型3.3 避免不必要的类型转换 4. 预防措施4.1 使用泛型和注解4.2 编写防御性代码4.3 使用注解和检查工具 5. 示…...

OpenCV-最小外接圆cv::minEnclosingCircle

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 函数原型 void minEnclosingCircle(InputArray points, Point2f& center, float& radius); 参数说明 InputArray类型的…...

大小堆运用巧解数据流的中位数

​​​​​​​​​​ 一、思路 我们将所有数据平分成两份&#xff0c;前面那一部分用小堆来存&#xff0c;后面的部分用大堆来存&#xff0c;这样我们就能立刻拿到中间位置的值。 如果是奇数个数字&#xff0c;那么我们就将把中间值放在前面的大堆里&#xff0c;所以会有两种…...

AI能力边界不断扩展,将对国家安全产生深远影响

文 | 中国信息安全测评中心 王欣 随着 ChatGPT 的发布及相关应用的落地&#xff0c;人工智能技术给全球各个行业带来了一波又一波冲击。GPT-4 多模态大型语言模型更是将人工智能的能力提升到新的高度&#xff0c;无论从技术先进性还是应用实践能力来看&#xff0c;此模型均可被…...

【UnityShader入门精要学习笔记】第十六章 Unity中的渲染优化技术 (上)

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 我的GitHub仓库 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 移动平台上…...

GPT-4o:免费且更快的模型

OpenAI GPT-4o 公告 OpenAI 推出了增强版 GPT-4 模型——OpenAI GPT-4o&#xff0c;用于支持 ChatGPT。首席技术官 Mira Murati 表示&#xff0c;更新后的模型速度更快&#xff0c;并在文本、视觉和音频处理方面有了显著提升。GPT-4o 将免费向所有用户开放&#xff0c;付费用户…...

docker部署fastdfs

我的镜像包地址 链接&#xff1a;https://pan.baidu.com/s/1j5E5O1xdyQVfJhsOevXvYg?pwdhcav 提取码&#xff1a;hcav docker load -i gofast.tar.gz拉取gofast docker pull sjqzhang/go-fastdfs启动gofast docker run -d --name fastdfs -p 8080:8080 -v /opt/lijia/lijia…...

【劲舞团game】

编写《劲舞团》这样的游戏代码是一个复杂的过程&#xff0c;涉及到游戏引擎的使用、图形渲染、物理模拟、音频处理、网络通信等多个方面。以下是一个非常简化的步骤&#xff0c;用于说明如何开始编写一个基于Unity引擎的简单舞蹈游戏&#xff1a; 1. 准备开发环境 下载并安装…...

Day15—图像爬虫与简单处理

图像爬虫是一种专门用于从互联网上下载图像的网络爬虫。除了文本内容,图像也是网站中的重要组成部分,它们可以用于多种目的,如图像识别、内容分析、数据备份等。 环境准备 首先,确保你的环境中已安装Python和必要的库。如果没有安装Pillow库,可以通过以下命令安装:pip in…...

Rust基础学习-Rust中的文件操作

文件结构 在Rust中&#xff0c;std::fs::File 结构体代表一个文件。它允许我们对文件执行读/写操作。文件 I/O 是通过提供与文件系统交互的功能的 std::fs 模块执行的。 File 结构体中的所有方法都返回std::io::Result的变体&#xff0c;或者简单地是 Result 枚举。这里会涉及…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...