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的基础语法的学习后,更进一步为应用场景多写代码.其中设计模式是有较大应用空间. 引入 原本在写容器中适配器类有关的帖子,发现适配模式需要先了解,于是试着先写篇和适配器模式相关的帖子 理解什么是适配器类,需要知道什么是适配器模式.适配器模式是设计模式的一种.笔…...
“八股文“在现代编程面试中的角色重塑:助力、阻力还是桥梁?
🌈所属专栏:【其它】✨作者主页: Mr.Zwq✔️个人简介:一个正在努力学技术的Python领域创作者,擅长爬虫,逆向,全栈方向,专注基础和实战分享,欢迎咨询! 您的点…...
Android 安装应用-浏览阶段
应用安装的浏览阶段主要是由PackageManagerService类中的scanPackageNewLI()实现的,看一下它的代码: // 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关键字(双重检查锁定) 一. 设计模式 设计模式是在软件工程中解决常见问题的经典解决方案。针对一些特定场景给出的一些比较好的解决…...
Javascript常见设计模式
JS设计模式学习【待吸收】-CSDN博客 JavaScript 中的设计模式是用来解决常见问题的最佳实践方案。这些模式有助于创建可重用、易于理解和维护的代码。下面列出了一些常见的 JavaScript 设计模式及其代码示例。 1. 单例模式(Singleton) 单例模式确保一…...
JavaFX布局-SplitPane
JavaFX布局-SplitPane 常用属性orientationpaddingdividerPositionsdisable 实现方式Java实现fxml实现 一个拆分至少两个区域的容器支持水平、垂直布局可以拖动区域的大小初始化大小通过比例设置[0,1] 常用属性 orientation 排列方式,Orientation.VERTICAL、Orien…...
2.MySQL库的操作
创建数据库 创建数据库的代码: CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [,create_specification] ...];create_specification:[DEFAULT] CHARACTER SET charset_name[DEFAULT] COLLATE collation_name 说明: 大写的表示关键…...
如何学习计算机
不要只盯着计算机语言学习,你现在已经学习了C语言和Java,暑假又规划学习Python,最后你掌握的就是计算机语言包而已。 2. 建议你找一门想要深挖的语言,沿着这个方向继续往后学习知识就行。计算机语言是学不完的,而未来就…...
Spring MVC 快速入门指南及实战演示
1、SpringMVC简介 1.1 背景 Servlet属于web层开发技术,技术特点: 1. 每个请求都需要创建一个Servlet进行处理 2. 创建Servlet存在重复操作 3. 代码灵活性低,开发效率低 是否有技术方案可以解决以上问题? 1.2 SpringMVC概述 Sp…...
在线测评系统(未完结)
文章目录 注意!!!1、多模块开发(后端)(1).Maven依赖(2)swagger配置 2、判题机开发(1)docker 前言:大二刚开始接手了本学院的oj,并管理了一段时间,后来老师给我…...
Python 爬虫项目实战(一):破解网易云 VIP 免费下载付费歌曲
前言 网络爬虫(Web Crawler),也称为网页蜘蛛(Web Spider)或网页机器人(Web Bot),是一种按照既定规则自动浏览网络并提取信息的程序。爬虫的主要用途包括数据采集、网络索引、内容抓…...
PTA 6-7 统计某类完全平方数
6-7 统计某类完全平方数(20分) 本题要求实现一个函数,判断任一给定整数N是否满足条件:它是完全平方数,又至少有两位数字相同,如144、676等。 函数接口定义: int IsTheNumber ( const int N );…...
PyFilesystem2 - Python 操作文件系统
文章目录 一、关于 PyFilesystem2二、安装三、快速使用四、指南为什么要使用 PyFilesystem ?打开文件系统树打印关闭目录信息子目录处理文件遍历 WalkingGlobbing移动和复制 五、概念路径系统路径沙盒错误 六、资源信息信息对象命名空间基本命名空间细节命名空间访问…...
Bug小记:关于servlet后端渲染界面时出现的问题小记1P
问题1: 问题描述: int delete(Integer Sno);后端在该方法调用时传入参数 req.getParameter("Sno")报错参数应该为Integer类型问题分析:后端通过请求获取到的前端数据都是字符串类型,需要手动转换参数类型 解决方法&a…...
智慧水务项目(二)django(drf)+angular 18 创建通用model,并对orm常用字段进行说明
一、说明 上一篇文章建立一个最简单的项目,现在我们建立一个公共模型,抽取公共字段,以便于后续模块继承,过程之中会对orm常用字段进行说明,用到的介绍一下 二、创建一个db.py 目录如下图 1、代码 from importlib im…...
<数据集>人员摔倒识别数据集<目标检测>
数据集格式:VOCYOLO格式 图片数量:8605张 标注数量(xml文件个数):8605 标注数量(txt文件个数):8605 标注类别数:1 标注类别名称:[fall] 序号类别名称图片数框数1fall860512275 使用标注工具…...
npm install 报错 ‘proxy‘ config is set properly. See: ‘npm help config‘
解决 参考链接:npm install 报错 ‘proxy‘ config is set properly. See: ‘npm help config‘-阿里云开发者社区 (aliyun.com)...
爬虫问题---ChromeDriver的安装和使用
一、安装 1.查看chrome的版本 在浏览器里面输入 chrome://version/ 回车查看浏览器版本 Chrome的版本要和ChromeDriver的版本对应,否则会出现版本问题。 2.ChromeDriver的版本选择 114之前的版本: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的代码生成艺术:利用编译器后端释放潜能 Perl,作为一种解释型语言,通常不通过编译器后端直接生成机器代码。然而,通过一些高级技术,Perl 程序员可以利用编译器后端来生成代码,从而提高性能或实现特…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
