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

news2024/9/23 11:25:49

前言

     
         在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.单点:咖啡,蛋糕,龟苓膏,凉茶任选其一.

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

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

关于适配器模式

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1976627.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文阅读】PETRv2: A Unified Framework for 3D Perception from Multi-Camera Images

Q: 论文如何解决这个问题&#xff1f; A: 论文通过提出PETRv2框架来解决多相机图像的3D感知问题&#xff0c;具体方法包括以下几个关键点&#xff1a; 时间建模&#xff08;Temporal Modeling&#xff09;&#xff1a; 通过3D坐标对齐&#xff08;3D Coordinates Alignment&…

AI应用开发前景与目标

前景与目标 什么是AIGC AIGC最基本的能力是生成内容&#xff0c;包括文本、图像、视频、代码、3D内容或者几种媒介类型转换组合 形成的“多模态内容”。生成算法、预训练模型、多模态等技术累积融合&#xff0c;以及深度模型方面的 技术创新&#xff0c;共同催生了AIGC的大爆…

一篇文章教你如何在Android上使用QPython高效编程

导语&#xff1a;你是否想在Android设备上体验Python编程的乐趣&#xff1f;QPython是一款强大的Python脚本引擎&#xff0c;让你在手机上也能轻松编写和运行Python代码。本文将带你了解QPython的使用方法&#xff0c;让你随时随地开启编程之旅&#xff01; 一、认识QPython Q…

File 34

package File;import java.awt.*; import java.io.File;public class file1 {public static void main(String[] args) {//创建FILE对象&#xff0c;指代某个具体的文件//路径分隔符File f1new File("C:/Users/SUI/Desktop/kaishi/nih.txt");// File f1new File(&quo…

推荐4款比转转大师还好用的专业数据恢复软件。

数据已经成为我们生活和工作中不可或缺的一部分&#xff1b;然而我们在很多的场景当中都会导致数据丢失&#xff1b;于是数据恢复工具便成了一些人的常用工具。很多人都知道转转大师数据恢复软件&#xff0c;但是也有其他的恢复软件也很好用。 1、福昕恢复 直通车&#xff1a;…

ArkTS通用属性

目录 一、尺寸设置 宽高&#xff0c;外边距&#xff0c;内边距&#xff0c;尺寸size layoutWeight constraintSize 二、位置设置 align direction position offset 使用Edge方式position,offset 三、布局约束 aspectRatio displayPriority 四、Flex布局 flexBas…

数字转罗马字符

import java.util.Scanner;/*** author gyf* ClassName Test* Date 2024/7/31 17:14* Version V1.0* Description : 方法一*/ public class Test {public static void main(String[] args) {Scanner scanner new Scanner(System.in);System.out.println("请输入一个字符串…

php类与对象

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理php类与对象相关的知识点 适合有编程基础的人观看 因为我这个也是整理第n语言&#xff0c;这些老套的概念就不再多啰嗦了。 直接整理相应的语法 感觉把php当第一语言学的人不太多了 快速理解类与对…

MyBatis的example.createCriteria()方法学习记录

目录 一、mapper的crud方法:1. insert方法insert(User user)insertSelective(User user) 2. select方法selectByPrimaryKey(id)selectByExample(example)selectCountByExample(example) 3. update方法updateByPrimaryKey(User user)updateByPrimaryKeySelective(User user)upda…

从零开始的MicroPython(六)ADC

上一篇&#xff1a;PWM 文章目录 ADC是什么ESP32的ADC代码 ADC是什么 ADC的英文全称是Analog / Digital Converter&#xff0c;是将模拟信号转换为数字信号的转换器&#xff0c;ADC是单片机读取传感器信号的常见方式。 我们日常生活中的信号&#xff0c;例如光照强度&#xf…

机器学习练手(三):基于决策树的iris 多分类和波士顿房价预测

总结&#xff1a;本文为和鲸python 可视化探索训练营资料整理而来&#xff0c;加入了自己的理解&#xff08;by GPT4o&#xff09; 原活动链接 原作者&#xff1a;vgbhfive&#xff0c;多年风控引擎研发及金融模型开发经验&#xff0c;现任某公司风控研发工程师&#xff0c;对…

python通过pyautogui自动给微信聊天窗口发消息

使用py脚本自动给聊天窗口发消息 1.突然的自我2.编写脚本玩一把i.先获取窗口位置ii.模拟聊天iii.疗效不错呢 1.突然的自我 突然想到pyautogui可以做那么事情&#xff0c; 那么是不是可以模拟聊天呢&#xff0c;如果结合现在的大模型chatGPT一边问然后得到结果一边自动和别人聊…

一文读懂新版Nacos的使用方式

文章目录 什么是 NacosNacos 架构Nacos 的本地启动 构建提供者 provider-nacos-8081搭建环境编写配置文件 application.yaml构建数据库编写业务实体类控制器类逻辑层与数据层接口 模块结构 构建消费者 consumer-nacos-8080搭建环境编写 yaml 文件配置编写业务编写配置类编写 Co…

Linux系统之NFS服务配置

准备工作 克隆两台linux&#xff0c;并更改其Mac地址&#xff0c;作为NFS客户端&#xff1b;将服务器更名为学号nfsserver&#xff0c;配置IP地址为192.168.学号.1 将客户端Client1更名为学号client1&#xff0c;配置IP地址为192.168.学号.2 将客户端Client2更名为学号clien…

达梦数据库一体机在宜昌市财政局上线了!

财政作为国家治理的基础和重要支柱&#xff0c;其数字化转型已成为构建现代财政制度的必由之路&#xff0c;引领着财政管理体系向更高效、更智能的方向迈进。 达梦数据全面助力财政信息化转型与智能化发展&#xff0c;采用 DAMEGN PAI I 系列数据库一体机&#xff0c;为宜昌市财…

python实现图像分割算法3

python实现区域增长算法 算法原理基本步骤数学模型Python实现详细解释优缺点应用领域区域增长算法是一种经典的图像分割技术,它的目标是将图像划分为多个互不重叠的区域。该算法通过迭代地合并与种子区域相似的邻域像素来实现分割。区域增长算法通常用于需要精确分割的场景,如…

css实现文字根据条件渐变

body 选择器 body { padding: 50vh 0; text-align: center; font-size: 6em; } padding: 50vh 0; 设置了body的上下内边距为视口高度的50%&#xff0c;左右内边距为0。text-align: center; 使得body内的文本内容居中显示。font-size: 6em; 设置了字体大小为当前字体尺寸的6倍…

Solana 自建节点搭建教程:手把手教你成为区块链网络的重要一员

区块链技术正在迅速改变世界&#xff0c;而Solana作为新一代高性能公链&#xff0c;以其出色的性能和低廉的交易费用吸引了众多开发者和用户。如果你想成为Solana生态系统的一部分&#xff0c;搭建自己的Solana节点是一个绝佳的选择。本教程将详细介绍如何一步步搭建Solana自建…

MyBatis 如何通过拦截器修改 SQL

目录 1. 实现Interceptor接口2. 注册配置文件 假如我们想实现多租户&#xff0c;或者在某些 SQL 后面自动拼接查询条件。在开发过程中大部分场景可能都是一个查询写一个 SQL 去处理&#xff0c;我们如果想修改最终 SQL 可以通过修改各个 mapper.xml 中的 SQL 来处理。 但实际过…

【C语言】结构体内存布局解析——字节对齐

&#x1f984;个人主页:小米里的大麦-CSDN博客 &#x1f38f;所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html &#x1f381;代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录 一、引言 二、什么是字节对齐&…