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

C++进阶:设计模式___适配器模式

前言

     
         在C++的基础语法的学习后,更进一步为应用场景多写代码.其中设计模式是有较大应用空间.

引入

        原本在写容器中适配器类有关的帖子,发现适配模式需要先了解,于是试着先写篇和适配器模式相关的帖子

         理解什么是适配器类,需要知道什么是适配器模式.适配器模式是设计模式的一种.笔者也准备开这个系列的专题,这里就当首个模式介绍.

从接口说起

        接口和实现的关系如图所示 

 

         

         

        这个图可以看成一切设计模式的起源.各种设计模式都可以从本图中演化出来----当然实际操作起来会远远难于一张图(笔者的思维习惯是概念极简,就好像之前把程序看成只做了两件事:修改数据和映射数据到硬件一样).

        接口是一种功能,一个需求;实现类是一种实现,多个实现类是多种实现.就好像变量代表所有能表示的常量.接口和实现的关系类似于变量和常量.接口是"虚"的,实现是"实"的.

        举例:有个喝下午茶的需求,有中式下午茶,吃龟苓膏,喝凉茶;有西式下午茶,喝咖啡,吃蛋糕.用接口与实现表达出来.

/*接口与实现*/
#include<iostream>
using namespace std;//抽象基类(接口)定义
class Abs_AfternoonTea {
public:virtual void	eat() = 0;	//纯虚方法:功能需求
};//中式下午茶定义
class ChineseTea :public Abs_AfternoonTea{int room_number;			//餐厅房间号码
public:ChineseTea(int ro) :room_number(ro) {};void Guiling_paste(){ cout << "吃龟苓膏" << endl; }void cold_tea(){cout<< "喝凉茶" << endl;}
//	int getRoomNumber() { return room_number; }void eat() { cout << "在" << room_number << "号房间享用下午茶:" << endl;Guiling_paste();cold_tea();}
};//西式下午茶定义
class WestTea :public Abs_AfternoonTea {int room_number;			//餐厅房间号码
public:WestTea(int ro) :room_number(ro) {};void coffee() { cout << "喝咖啡" << endl; }void cake() { cout << "吃蛋糕" << endl; }int getRoomNumber() { return room_number; }void eat() {cout << "在" << room_number << "号房间享用下午茶:" << endl;coffee();cake();}
};

        测试代码

int main(void) {ChineseTea ct(3);Abs_AfternoonTea& aat = ct;aat.eat();
}

----这种方案的是接口和实现直接对接,没问题

    回顾:需求:下午茶; 实现1:中式下午茶; 实现2:西式下午茶

    现在喝下午茶的需求做一点改变:喝凉茶,吃蛋糕;(中式西式各占一个).如果再按"接口-实现"的方式来设计代码架构,就得再设计一个类MixTea,如下所示: 

//混合下午茶定义
class MixTea :public Abs_AfternoonTea {int room_number;			//餐厅房间号码
public:WestTea(int ro) :room_number(ro) {};void cold_tea() { cout << "喝凉茶" << endl; }void cake() { cout << "吃蛋糕" << endl; }void eat() {cout << "在" << room_number << "号房间享用下午茶:" << endl;cold_tea();cake();}
};

        测试代码:

int main(void) {MixTea mt(3);Abs_AfternoonTea& aat = mt;aat.eat();
}

        问题并没有完全解决,如果下次的需求再改变:喝咖啡,吃龟苓膏.又得再设计一个类,依次类推.

        所以得出结论:

                接口-实现的直接架构是万能的,但扩展性不好

        为了让接口更好地被实现,需要对现有代码修改.适配器登场.

适配器适应方案选择 

        适配器思路:接口由适配器实现(适配器类继承接口).适配器是一个间接类,具体怎么实现由他所包含的对象来决定. 现在把工作细化,每个工作配一个厨师(龟苓膏,凉茶,咖啡,蛋糕各自由一个厨师来做).下面是为适配器准备的类

        接口和适配器类.h

/*适配器以下类定义*/
#include<iostream>
using namespace std;
/*定义厨师类及派生类*/
class Chef {											//厨师类string name;
public:Chef(const string& na):name(na){}string getName() { return name; }					//获得名称virtual void make_food() {};						//虚方法,做食物
}; class Cake_division :public Chef {						//蛋糕师类
public:Cake_division(const string& st) :Chef(st) {}void make_cake() { cout << getName()<<"做蛋糕" << endl; }virtual void make_food(){ make_cake(); }
};class Barista :public Chef {							//咖啡师类
public:Barista(const string& st) :Chef(st) {}void make_coffee() { cout << getName() << "冲咖啡" << endl; }virtual void make_food() { make_coffee(); }
};class Guilinggao_master :public Chef {					//龟苓膏师傅类
public:Guilinggao_master(const string& st) :Chef(st){}void make_Guilinggao() { cout << getName() << "做龟苓膏" << endl; }virtual void make_food() { make_Guilinggao(); }
};class Herbal_tea_master :public Chef {					//凉茶师傅类
public:Herbal_tea_master(const string& st) :Chef(st) {}void make_Herbal_tea() { cout << getName() << "做凉茶" << endl; }virtual void make_food() { make_Herbal_tea(); }
};/*以下为单组食物适配器定义的类*/
class SingleGroup {										//单组接口string name;
public:SingleGroup(const string& st):name(st) {}virtual void eat() {};
};class ChineseTeaGroup :public SingleGroup{				//中式下午茶类Guilinggao_master& gm;Herbal_tea_master& hm;
public:ChineseTeaGroup(Guilinggao_master& g, Herbal_tea_master& h, const string& st):gm(g),hm(h), SingleGroup(st){}void eat() { gm.make_food(); hm.make_food(); }
};class WestTeaGroup :public SingleGroup {				//西式下午茶类Cake_division& cd;Barista& ba;
public:WestTeaGroup(Cake_division& c, Barista& b, const string& st):cd(c),ba(b),SingleGroup(st){}void eat() { cd.make_food(); ba.make_food(); }
};/*以下为混合食物适配器定义的类*/
/*不想使用多重继承,用包含把厨师对象拿过来*/
class MixChineseTeaGroup {								//中式下午茶(混合)类string name;
public:MixChineseTeaGroup(const string& st):name(st){}virtual void eat(){}
};class MixGuilinggao:public MixChineseTeaGroup {			//龟苓膏(混合)类Guilinggao_master& gm;
public:MixGuilinggao(Guilinggao_master& g,const string& st) :gm(g) ,MixChineseTeaGroup(st){}void eat() { gm.make_food();  }
};class MixHerbal :public MixChineseTeaGroup {			//凉茶(混合)类Herbal_tea_master& hm;;
public:MixHerbal(Herbal_tea_master& h, const string& st) :hm(h), MixChineseTeaGroup(st) {}void eat() { hm.make_food(); }
};class MixChineseDouble :public MixChineseTeaGroup {		//中式下午茶两个一起类Guilinggao_master& gm;Herbal_tea_master& hm;
public:MixChineseDouble(Guilinggao_master& g, Herbal_tea_master& h, const string& st) :gm(g), hm(h), MixChineseTeaGroup(st) {}void eat() { gm.make_food(); hm.make_food(); }
};class MixWestTeaGruop {									//西式下午茶(混合)总类string name;
public:MixWestTeaGruop(const string& st) :name(st) {}virtual void eat() {}
};class MixCake :public MixWestTeaGruop {					//蛋糕类(混合)						Cake_division& cn;
public:MixCake(Cake_division& c, const string& st):cn(c),MixWestTeaGruop(st){}void eat() { cn.make_food(); }
};class MixBarista :public MixWestTeaGruop {				//咖啡类(混合)Barista& ba;
public:MixBarista(Barista& b, const string& st) :ba(b), MixWestTeaGruop(st) {}void eat() { ba.make_food(); }
};class MixWestDouble :public MixWestTeaGruop {			//西式下午茶两个一起类Cake_division& cd;Barista& ba;
public:MixWestDouble(Cake_division& c, Barista& b, const string& st) :cd(c), ba(b), MixWestTeaGruop(st) {}void eat() { cd.make_food(); ba.make_food(); }
};

 接口和适配器类.cpp

/*适配器及接口定义*/
#include<iostream>
#include<string>
#include"接口和适配器.h"
using namespace std;//抽象基类(接口)定义
class Abs_AfternoonTea {
public:virtual void	eat() = 0;							//纯虚方法:功能需求
};//单组适配器定义
class SingleGroup_Adapter :public Abs_AfternoonTea {SingleGroup& sg;
public:SingleGroup_Adapter(SingleGroup& s):sg(s){}virtual void eat() { sg.eat(); }
};//混组适配器定义
class MixGroup_Adapter :public Abs_AfternoonTea {MixChineseTeaGroup& mcg;MixWestTeaGruop& mwg;
public:MixGroup_Adapter(MixChineseTeaGroup& mc, MixWestTeaGruop& mw):mcg(mc),mwg(mw){}virtual void eat() { mcg.eat(); mwg.eat(); }
};//单点适配器定义
class SingleFood_Adapter :public Abs_AfternoonTea {Chef& cf;
public:SingleFood_Adapter(Chef& c):cf(c){}virtual void eat() { cf.make_food(); }
};

        测试代码        

int main(void) {/*单吃蛋糕*/Cake_division cd("小张");								//生成蛋糕师对象
//	 Chef& cf = cd;											//厨师对象生成SingleFood_Adapter sfa(cd);							//单点适配器对象生成Abs_AfternoonTea& aat = sfa;							//转向接口aat.eat();cout << "===============分隔线============" << endl;/*中式下午茶组*/Guilinggao_master xw("小王");Herbal_tea_master xl("小李");ChineseTeaGroup cg(xw, xl,"中式下午茶");SingleGroup& sg = cg;SingleGroup_Adapter sa = SingleGroup_Adapter(cg);		//单组适配器对象生成Abs_AfternoonTea& aat1 = sa;							//转向接口aat1.eat();cout << "===============分隔线============" << endl;/*混合下午茶*/MixChineseDouble md(xw, xl,"混合下午茶");MixChineseTeaGroup& mtg = md;MixCake mc(cd, "xiaozhang");MixWestTeaGruop& mg = mc;MixGroup_Adapter ma = MixGroup_Adapter(mtg, mg);		//混合适配器对象生成Abs_AfternoonTea& aat2 = ma;							//转向接口aat2.eat();
}

================================内容分割线================================ 

         代码有打磨空间,一是能否去掉不相关的属性;二是引入客户指令---测试是自己写的条件,客户指令处理可以加进来

================================内容分割线================================ 

代码说明

        第一,看见密密麻麻的代码,为了一个小问题增加许多是否值得?

                代码多,但是表达的意思并不是很多,只是看起来多而已.

                值得不值得,这个得根据需求来.只要能满足客户需求就是值得的. 

        第二,可以实现哪些功能?

                1.单个组合:西式下午茶--咖啡和蛋糕套餐  (或)

                                   中式下午茶--龟苓膏和凉茶套餐

                2.混合点餐:咖啡,蛋糕,龟苓膏,凉茶任选其二以上(单点不行)

                3.单点:咖啡,蛋糕,龟苓膏,凉茶任选其一.

         第三,为什么有感觉重复的类?

                笔者暂时不会多重继承,也不知道多重继承是否适合.所以定义了多个类.测试可以的

关于适配器模式

        在接口--实现的过程中,加了适配器一层.适配器的作用简单描述就是继承接口,包含相关类 

        此外,适配器模式容易扩展.比如在此代码基础上,继续用适配器扩展,加入更多功能,也是很方便的. 

相关文章:

C++进阶:设计模式___适配器模式

前言 在C的基础语法的学习后,更进一步为应用场景多写代码.其中设计模式是有较大应用空间. 引入 原本在写容器中适配器类有关的帖子,发现适配模式需要先了解,于是试着先写篇和适配器模式相关的帖子 理解什么是适配器类,需要知道什么是适配器模式.适配器模式是设计模式的一种.笔…...

“八股文“在现代编程面试中的角色重塑:助力、阻力还是桥梁?

&#x1f308;所属专栏&#xff1a;【其它】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点…...

Android 安装应用-浏览阶段

应用安装的浏览阶段主要是由PackageManagerService类中的scanPackageNewLI()实现的&#xff0c;看一下它的代码&#xff1a; // TODO: scanPackageNewLI() and scanPackageOnly() should be merged. But, first, commiting// the results / removing app data needs to be move…...

JavaEE 初阶(10)——多线程8之“单例模式”

目录 一. 设计模式 二. 单例模式 2.1 饿汉模式 2.2 懒汉模式 a. 加锁synchronized b. 双重if判定 c. volatile关键字&#xff08;双重检查锁定&#xff09; 一. 设计模式 设计模式是在软件工程中解决常见问题的经典解决方案。针对一些特定场景给出的一些比较好的解决…...

Javascript常见设计模式

JS设计模式学习【待吸收】-CSDN博客 JavaScript 中的设计模式是用来解决常见问题的最佳实践方案。这些模式有助于创建可重用、易于理解和维护的代码。下面列出了一些常见的 JavaScript 设计模式及其代码示例。 1. 单例模式&#xff08;Singleton&#xff09; 单例模式确保一…...

JavaFX布局-SplitPane

JavaFX布局-SplitPane 常用属性orientationpaddingdividerPositionsdisable 实现方式Java实现fxml实现 一个拆分至少两个区域的容器支持水平、垂直布局可以拖动区域的大小初始化大小通过比例设置[0,1] 常用属性 orientation 排列方式&#xff0c;Orientation.VERTICAL、Orien…...

2.MySQL库的操作

创建数据库 创建数据库的代码&#xff1a; CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [,create_specification] ...];​create_specification:[DEFAULT] CHARACTER SET charset_name[DEFAULT] COLLATE collation_name 说明&#xff1a; 大写的表示关键…...

如何学习计算机

不要只盯着计算机语言学习&#xff0c;你现在已经学习了C语言和Java&#xff0c;暑假又规划学习Python&#xff0c;最后你掌握的就是计算机语言包而已。 2. 建议你找一门想要深挖的语言&#xff0c;沿着这个方向继续往后学习知识就行。计算机语言是学不完的&#xff0c;而未来就…...

Spring MVC 快速入门指南及实战演示

1、SpringMVC简介 1.1 背景 Servlet属于web层开发技术&#xff0c;技术特点&#xff1a; 1. 每个请求都需要创建一个Servlet进行处理 2. 创建Servlet存在重复操作 3. 代码灵活性低&#xff0c;开发效率低 是否有技术方案可以解决以上问题&#xff1f; 1.2 SpringMVC概述 Sp…...

在线测评系统(未完结)

文章目录 注意&#xff01;&#xff01;&#xff01;1、多模块开发&#xff08;后端&#xff09;(1).Maven依赖(2)swagger配置 2、判题机开发&#xff08;1&#xff09;docker 前言&#xff1a;大二刚开始接手了本学院的oj&#xff0c;并管理了一段时间&#xff0c;后来老师给我…...

Python 爬虫项目实战(一):破解网易云 VIP 免费下载付费歌曲

前言 网络爬虫&#xff08;Web Crawler&#xff09;&#xff0c;也称为网页蜘蛛&#xff08;Web Spider&#xff09;或网页机器人&#xff08;Web Bot&#xff09;&#xff0c;是一种按照既定规则自动浏览网络并提取信息的程序。爬虫的主要用途包括数据采集、网络索引、内容抓…...

PTA 6-7 统计某类完全平方数

6-7 统计某类完全平方数&#xff08;20分&#xff09; 本题要求实现一个函数&#xff0c;判断任一给定整数N是否满足条件&#xff1a;它是完全平方数&#xff0c;又至少有两位数字相同&#xff0c;如144、676等。 函数接口定义&#xff1a; int IsTheNumber ( const int N );…...

PyFilesystem2 - Python 操作文件系统

文章目录 一、关于 PyFilesystem2二、安装三、快速使用四、指南为什么要使用 PyFilesystem &#xff1f;打开文件系统树打印关闭目录信息子目录处理文件遍历 WalkingGlobbing移动和复制 五、概念路径系统路径沙盒错误 六、资源信息信息对象命名空间基本命名空间细节命名空间访问…...

Bug小记:关于servlet后端渲染界面时出现的问题小记1P

问题1&#xff1a; 问题描述&#xff1a; int delete(Integer Sno);后端在该方法调用时传入参数 req.getParameter("Sno")报错参数应该为Integer类型问题分析&#xff1a;后端通过请求获取到的前端数据都是字符串类型&#xff0c;需要手动转换参数类型 解决方法&a…...

智慧水务项目(二)django(drf)+angular 18 创建通用model,并对orm常用字段进行说明

一、说明 上一篇文章建立一个最简单的项目&#xff0c;现在我们建立一个公共模型&#xff0c;抽取公共字段&#xff0c;以便于后续模块继承&#xff0c;过程之中会对orm常用字段进行说明&#xff0c;用到的介绍一下 二、创建一个db.py 目录如下图 1、代码 from importlib im…...

<数据集>人员摔倒识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;8605张 标注数量(xml文件个数)&#xff1a;8605 标注数量(txt文件个数)&#xff1a;8605 标注类别数&#xff1a;1 标注类别名称&#xff1a;[fall] 序号类别名称图片数框数1fall860512275 使用标注工具&#xf…...

npm install 报错 ‘proxy‘ config is set properly. See: ‘npm help config‘

解决 参考链接&#xff1a;npm install 报错 ‘proxy‘ config is set properly. See: ‘npm help config‘-阿里云开发者社区 (aliyun.com)...

爬虫问题---ChromeDriver的安装和使用

一、安装 1.查看chrome的版本 在浏览器里面输入 chrome://version/ 回车查看浏览器版本 Chrome的版本要和ChromeDriver的版本对应&#xff0c;否则会出现版本问题。 2.ChromeDriver的版本选择 114之前的版本&#xff1a;https://chromedriver.storage.googleapis.com/index.ht…...

Spring的配置类分为Full和Lite两种模式

Spring的配置类分为Full和Lite两种模式 首先查看 Configuration 注解的源码, 如下所示: Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented Component public interface Configuration {AliasFor(annotation Component.class)String value() defau…...

探索Perl的代码生成艺术:利用编译器后端释放潜能

探索Perl的代码生成艺术&#xff1a;利用编译器后端释放潜能 Perl&#xff0c;作为一种解释型语言&#xff0c;通常不通过编译器后端直接生成机器代码。然而&#xff0c;通过一些高级技术&#xff0c;Perl 程序员可以利用编译器后端来生成代码&#xff0c;从而提高性能或实现特…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...