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 程序员可以利用编译器后端来生成代码,从而提高性能或实现特…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...