当前位置: 首页 > 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;从而提高性能或实现特…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...