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

常用设计模式总结

复习到设计模式的时候写的一些demo代码

回头可以看看

单例的几种比较简单就没写了,专栏有

目录

观察者(发布--订阅模式)模式,多个对象依赖于一个对象,或者多对多

工厂模式:主要是封装了对象的创建(简单,方法,抽象)

简单工厂,不在23种设计模式里

工厂方法:

抽象方法:

结构型模式

代理Proxy模式demo:

适配器模式

装饰器模式,Decorator


观察者(发布--订阅模式)模式,多个对象依赖于一个对象,或者多对多

/*subject有更改 要及时通知observer去做改变
*/
class Observer{//观察者抽象类//处理消息接口public:virtual void handleEvent(int msgid)=0;
};
class Observer1:public Observer{public:void handleEvent(int msgid){ //做出相应动作switch (msgid){case 1:cout<<"Observer1 received 1"<<endl;break;case 2:cout<<"Observer1 received 2"<<endl;break;default:cout<<"Observer1 received unknown"<<endl;break;}}
};
class Observer2:public Observer{public:void handleEvent(int msgid){ //做出相应动作switch (msgid){case 2:cout<<"Observer2 received 2"<<endl;break;default:cout<<"Observer2 received unknown"<<endl;break;}}
};
//主题
class Subject{  private:unordered_map<int,list<Observer*>> _subMap;public://给主题增加观察者对象void addObserver(Observer *obser,int msgid){_subMap[msgid].push_back(obser);}//主题改变 ,通知相应的观察者去处理事件void notifyObservers(int msgid){auto it = _subMap.find(msgid);if(it != _subMap.end()){//找到了for(Observer *ob:it->second){ob->handleEvent(msgid);}}}};int main(){Subject subject;Observer *p1=new Observer1();Observer *p2=new Observer2();subject.addObserver(p1,1);subject.addObserver(p1,2);subject.addObserver(p1,3);subject.addObserver(p2,2);subject.addObserver(p2,3);int msgid;while(1){cout<<"消息id: "<<endl;cin>>msgid;subject.notifyObservers(msgid);if(msgid==-1){break;}}system("pause");return 0;
}

工厂模式:主要是封装了对象的创建(简单,方法,抽象)

简单工厂,不在23种设计模式里

简单工厂demo:把对象的创建封装在一个接口函数里,通过传入不同的标识,返回创建的对象,好处是客户不用自己负责new对象,不用了解对象具体创建的详细过程(这种设计模式不好)

缺点:提供创建对象实例的接口函数不闭合,不能对修改关闭

class Car{public:Car(string name):_name(name){}virtual void show()=0;protected:string _name;
};
class BMW:public Car
{public:BMW(string name):Car(name){}void show(){cout<<"宝马车"<<endl;}
};
class Audi:public Car
{public:Audi(string name):Car(name){}void show(){cout<<"奥迪车"<<endl;}
};enum CarType{BMw,AUDI
};
class SimpleFactory{   //封装了 对象public:Car* CreateCar(CarType type){switch(type){case BMw:return new BMW("X1");break;case AUDI:return new Audi("A6");break;default:cout<<"type err"<<endl;break;}return nullptr;}
};
int main(){SimpleFactory *fac=new SimpleFactory();Car *car=fac->CreateCar(BMw);Car *car1=fac->CreateCar(AUDI);car->show();car1->show();delete car;delete car1;delete fac;system("pause");return 0;
}

工厂方法:

把工厂划分成基类,各个子工厂去继承方法

相应的工厂只需要创建自己厂家的东西就行,还想增加奔驰,就多个奔驰工厂去继承工厂类,重写创建方法就好

对于已有的工厂不需要做改变,做到了软件工程的开闭原则

  • 工厂基类提供一个纯虚函数(创建产品),定义派生类(具体工厂),创建对应产品,可以做到不同的产品,在不同的工厂里创建,能够对现有的工厂和产品进行修改关闭
  • 实际上很多产品是有关联关系的,属于一个产品簇,不应该放在不同的工厂去创建
class Car{public:Car(string name):_name(name){}virtual void show()=0;protected:string _name;
};
class BMW:public Car
{public:BMW(string name):Car(name){}void show(){cout<<"宝马车"<<endl;}
};
class Audi:public Car
{public:Audi(string name):Car(name){}void show(){cout<<"奥迪车"<<endl;}
};//工厂方法
class Factory{
public:virtual Car* create(string name)=0;
};
//宝马工厂
class BMWFactory:public Factory{
public:Car* create(string name){return new BMW(name);}
};
//奥迪工厂
class AudiFactory:public Factory{
public:Car* create(string name){return new Audi(name);}
};
int main(){Factory *fac=new BMWFactory();Factory *fac1=new AudiFactory();Car *car=fac->create("BMw");Car *car1=fac1->create("AUDI");car->show();car1->show();delete car;delete car1;delete fac;delete fac1;system("pause");return 0;
}

抽象方法:

考虑生产一类产品,比如生产手机,耳机,充电器,总不能生产一种产品就创建一个工厂

上面的问题简单工厂无法解决,引入抽象工厂

其实就是把工厂方法叠加起来了,工厂基类的方法多了一些,子工厂继承的就多

把有关联的产品簇里的所有产品创建的接口函数,放在一个抽象工厂里,派生类(具体工厂)应该负责创建该产品簇里的所有产品

//系列产品1  汽车
class Car{public:Car(string name):_name(name){}virtual void show()=0;protected:string _name;
};
class BMW:public Car
{public:BMW(string name):Car(name){}void show(){cout<<"宝马车"<<_name<<endl;}
};
class Audi:public Car
{public:Audi(string name):Car(name){}void show(){cout<<"奥迪车"<<_name<<endl;}
};//系列产品2  车灯
class Light{public:    virtual void show()=0;
};
class BMWLight:public Light
{public: void show(){cout<<"宝马 车灯"<<endl;}
};
class AudiLight:public Light
{public:void show(){cout<<"奥迪 车灯"<<endl;}
};
//抽象工厂 对一组有关联关系的产品组提供产品的统一创建
class Factory{
public:virtual Car* createCar(string name)=0;//工厂方法virtual Light* createLight()=0;//工厂方法
};
//宝马工厂
class BMWFactory:public Factory{
public:Car* createCar(string name){return new BMW(name);}Light* createLight(){return new BMWLight();}};
//奥迪工厂
class AudiFactory:public Factory{
public:Car* createCar(string name){return new Audi(name);}Light* createLight(){return new AudiLight();}
};int main(){Factory *fac=new BMWFactory();Factory *fac1=new AudiFactory();Car *car=fac->createCar("BMw");Car *car1=fac1->createCar("AUDI");Light *l1=fac->createLight();Light *l2=fac1->createLight();car->show();l1->show();car1->show();l2->show();system("pause");return 0;
}

结构型模式

代理Proxy模式demo:

通过代理类来控制实际对象(委托类)的访问权限
客户    助理proxy   老板:委托类

class VideoSite{public:virtual void freeMovie()=0;//免费电影virtual void vipMovie()=0;//vip 电影virtual void ticketMovie()=0;//用劵
};
class FixBugVideoSite:public VideoSite{//委托类 拥有所有功能public:virtual void freeMovie(){cout<<"free movie"<<endl;}virtual void vipMovie(){cout<<"vip movie"<<endl;}virtual void ticketMovie(){cout<<"ticket movie"<<endl;}
};
//代理类 
class FreeVideoProxy:public VideoSite{
public:FreeVideoProxy(){PVideo =new FixBugVideoSite();}~FreeVideoProxy(){delete PVideo;}virtual void freeMovie(){PVideo->freeMovie();//通过代理对象的freemovie去访问真正委托类方法}virtual void vipMovie(){cout<<"you are free  cant use vip"<<endl;}virtual void ticketMovie(){cout<<"no ticket cant see movie"<<endl;}
private:VideoSite* PVideo;
};
//代理类 
class VipVideoProxy:public VideoSite{
public:VipVideoProxy(){PVideo =new FixBugVideoSite();}~VipVideoProxy(){delete PVideo;}virtual void freeMovie(){PVideo->freeMovie();//通过代理对象的freemovie去访问真正委托类方法}virtual void vipMovie(){PVideo->vipMovie();}virtual void ticketMovie(){cout<<"vip no ticket cant see movie"<<endl;}
private:VideoSite* PVideo;
};
int main()
{unique_ptr<VideoSite> p1(new FreeVideoProxy());p1->freeMovie();p1->vipMovie();p1->ticketMovie();system("pause");return 0;
}

适配器模式

让不兼容的接口可以在一起工作
电脑-》 投影到 -》 投影仪上 需要的线接口:VGA HDMI TypeC

VGA接口的电脑,投影仪也是VGA接口

HDMI的投影仪,就要用适配器去转换

class VGA{
public:virtual void play()=0;
};
//TV01表示支持VGA接口的投影仪
class TV01:public VGA{
public:void play(){cout<<"use VGA接口连接投影仪,进行视频播放"<<endl;}
};//电脑类(只支持VGA接口)
class HuaweiComputer{
public:void playVideo(VGA *vga){vga->play();}
};
/*
1.换支持hdmi接口的电脑,代码重构
2.买转换头(适配器),把vga信号转成hdmi信号,添加适配器类
*///进了一批新的投影仪,但是投影仪只支持HDMI接口
class HDMI{
public:virtual void play()=0;
};class TV02:public HDMI{
public:void play(){cout<<"use HDMI接口连接投影仪,进行视频播放"<<endl;}
};
//适配器类
class VGA_TO_HDMI:public VGA{
public:VGA_TO_HDMI(HDMI *p):pp(p){}void play(){//转换头pp->play();}
private:HDMI* pp;
};int main()
{HuaweiComputer c1;c1.playVideo(new TV01());c1.playVideo(new VGA_TO_HDMI(new TV02()));system("pause");return 0;
}

装饰器模式,Decorator

装饰器:增加现有类的功能

装饰器类持有需要被装饰的对象,装饰器再可以根据功能去细分子类

class Car{//抽象基类public:virtual void show()=0;
};
//实体类
class BMW:public Car{public:void show(){cout<<"is bmw common"<<endl;}
};
class Benz:public Car{public:void show(){cout<<"is Benz common"<<endl;}
}; 
//装饰器  定速巡航的功能
class ConcreteDecorator01:public Car{public:ConcreteDecorator01(Car *p):car(p) {}void show(){car->show();cout<<"is concrete"<<endl;}private:Car* car;
};
//装饰器  自动刹车功能
class StopDecorator01:public Car{public:StopDecorator01(Car *p):car(p) {}void show(){car->show();cout<<"is Stop"<<endl;}private:Car* car;
};int main()
{Car *p1=new ConcreteDecorator01(new Benz());p1->show();p1=new StopDecorator01(p1);p1->show();Car *p2=new StopDecorator01(new BMW());p2->show();system("pause");return 0;
}

相关文章:

常用设计模式总结

复习到设计模式的时候写的一些demo代码 回头可以看看 单例的几种比较简单就没写了&#xff0c;专栏有 目录 观察者&#xff08;发布--订阅模式&#xff09;模式&#xff0c;多个对象依赖于一个对象&#xff0c;或者多对多 工厂模式&#xff1a;主要是封装了对象的创建&…...

【算法基础】一维前缀和 + 二维前缀和

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;【C/C】算法 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有…...

Kafka消费分组和分区分配策略

Kafka消费分组&#xff0c;消息消费原理 同一个消费组里的消费者不能消费同一个分区&#xff0c;不同消费组的消费组可以消费同一个分区 &#xff08;即同一个消费组里面的消费者只能在一个分区中&#xff09; Kafka分区分配策略 问题 用过 Kafka 的同学用过都知道&#xf…...

犹太教、基督教、伊斯兰教的区别与联系

一、犹太教、基督教、伊斯兰教的简明关系图二、犹太教、基督教、伊斯兰教的主要区别注&#xff1a;弥赛亚&#xff08;希伯莱语&#xff09;就是基督&#xff08;希腊语&#xff09;&#xff0c;意思是“救世主”。注&#xff1a;伊斯兰教的观点是&#xff1a;穆罕默德不是伊斯…...

华为OD机试 - 打印文件(Python) | 机试题+算法思路+考点+代码解析 【2023】

打印文件 题目 有 5 台打印机打印文件,每台打印机有自己的待打印队列。 因为打印的文件内容有轻重缓急之分,所以队列中的文件有1~10不同的优先级,其中数字越大优先级越高。 打印机会从自己的待打印队列中选择优先级最高的文件来打印。 如果存在两个优先级一样的文件,则选…...

网络工程师必备知识点

作为网络工程师&#xff0c;您将负责设计、部署和维护计算机网络系统。这包括构建、配置和管理网络设备&#xff0c;如交换机、路由器、防火墙等&#xff0c;并确保网络系统能够高效地运行。您需要了解计算机网络的各个层次、协议、标准和技术&#xff0c;包括TCP/IP、DNS、HTT…...

数据在内存中的存储【下篇】

文章目录⚙️3.浮点型在内存中的存储&#x1f529;3.1.一个例子&#x1f529;3.2.浮点数的存储规则&#x1f529;3.3.例题解析⚙️3.浮点型在内存中的存储 &#x1f529;3.1.一个例子 &#x1f534;浮点数存储的例子&#xff1a;&#x1f447; int main() {int n 9;float* …...

前端开发项目规范写法介绍

1. 基本原则 结构、样式、行为分离 尽量确保文档和模板只包含 HTML 结构,样式都放到样式表里,行为都放到脚本里。 缩进 统一两个空格缩进(总之缩进统一即可),不要使用 Tab 或者 Tab、空格混搭。 文件编码 使用不带 BOM 的 UTF-8 编码。 在 HTML中指定编码 <meta c…...

百万医疗险是什么

一、百万医疗险是什么 从名字可以看出&#xff0c;这是一款医疗险。因为保额高&#xff0c;最高能报销百万&#xff0c;所以叫百万医疗险。 二、百万医疗险有什么用 可以报销被保险人因意外伤害和疾病导致的医疗费用 三、如何挑选 虽然高达几百万的保额&#xff0c;但保额却并非…...

矩阵中的路径 AcWing (JAVA)

请设计一个函数&#xff0c;用来判断在一个矩阵中是否存在一条路径包含的字符按访问顺序连在一起恰好为给定字符串。 路径可以从矩阵中的任意一个格子开始&#xff0c;每一步可以在矩阵中向左&#xff0c;向右&#xff0c;向上&#xff0c;向下移动一个格子。 如果一条路径经过…...

使用终端工具给你的电脑发送弹窗提醒

大家好&#xff0c;我是良许。 现在人手一部智能手机&#xff0c;这些智能手机都有个非常实用的功能&#xff0c;那就是弹窗提醒。当我们收到短信&#xff0c;或者微信信息时&#xff0c;手机就会弹窗显示信息的大致内容。有了这个功能你就不会错过重要信息了。 电脑上也有类…...

SpringCloud Alibaba 之Nacos集群部署-高可用保证

文章目录Nacos集群部署Linux部署docker部署&#xff08;参考待验证&#xff09;Nacos 集群的工作原理Nacos 集群中 Leader 节点是如何产生的Nacos 节点间的数据同步过程官方推荐用户把所有服务列表放到一个vip下面&#xff0c;然后挂到一个域名下面。http://nacos.com:port/ope…...

Scala集合详解(第七章:集合、数组、列表、set集合、map集合、元组、队列、并行)(尚硅谷笔记)

集合第七章:集合7.1 集合简介7.1.1 不可变集合继承图7.1.2 可变集合继承图7.2 数组7.2.1 不可变数组7.2.2 可变数组7.2.3 不可变数组与可变数组的转换7.2.4 多维数组7.3 列表 List7.3.1 不可变 List7.3.2 可变 ListBuffer7.4 Set 集合7.4.1 不可变 Set7.4.2 可变 mutable.Set7.…...

定了:Python3.7,今年停止更新~

大家好&#xff0c;这里是程序员晚枫。 今天给大家分享一个来自Python官网的重要消息&#xff1a;Python3.7马上就要停止维护了&#xff0c;请不要使用了&#xff01; 官网链接&#xff1a;https://devguide.python.org/versions/ 停更的后果是什么&#xff1f; 周末翻阅Py…...

C# 业务单据号生成器(定义规则、获取编号、流水号)

系列文章 C#底层库–数据库访问帮助类&#xff08;MySQL版&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/126886379 C#底层库–JSON帮助类_详细&#xff08;序列化、反序列化、list、datatable&#xff09; 本文链接&#xff1a;htt…...

Java的dump文件分析及JProfiler使用

Java的dump文件分析及JProfiler使用 1 dump文件介绍 从软件开发的角度上&#xff0c;dump文件就是当程序产生异常时&#xff0c;用来记录当时的程序状态信息&#xff08;例如堆栈的状态&#xff09;,用于程序开发定位问题。 idea配置发生OOM的时候指定路径生成dump文件 # 指定…...

sympy高斯光束模型

文章目录Gauss模型sympy封装实战sympy.phisics.optics.gaussopt集成了高斯光学中的常见对象&#xff0c;包括光线和光学元件等&#xff0c;有了这些东西&#xff0c;就可以制作一个光学仿真系统。Gauss模型 高斯光束的基本模型为 E(r,z)E0ω0ω(z)exp⁡[−r2ω2(z)]exp⁡[−ik…...

Cloudflared 内网穿透 使用记录

Cloudflared 内网穿透前提创建cloudflared tunnel我使用的服务前提 你必须要有一个域名&#xff0c;并且可以改域名的dns解析服务商到cloudflare 1.登录到cloudflare后台&#xff0c;点击添加站点 2.输入自己的域名&#xff0c;下一步选择免费套餐 3.他会搜索这个域名下已有…...

柴油发电机组的调压板

1 概述 柴油发电机组的调压板是一种用于控制发电机输出电压的装置。它通常由一块电子电路板和一个电子电路板上的电位器组成。 当发电机运行时&#xff0c;它会产生电压&#xff0c;然后通过调压板中的电路进行控制。调压板中的电路会检测输出电压的大小&#xff0c;并通过电…...

【MySQL】表操作和库操作

文章目录概念库操作1.创建数据库2.删除数据库3.选择数据库4.显示数据库列表表操作1.创建数据表CREATE2.删除数据表DROP3.插入数据INSERT4.更新数据UPDATE5.修改数据ALTER6.查询数据SELECT7.WHERE子句8.ORDER BY子句9.LIMIT子句10.GROUP BY子句11.HAVING子句使用注意事项概念 M…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...