C++_设计模式\_观察者模式(Observer Pattern)
- 👋 Hi, I’m liubo
- 👀 I’m interested in harmony
- 🌱 I’m currently learning harmony
- 💞️ I’m looking to collaborate on …
- 📫 How to reach me …
- 📇 sssssdsdsdsdsdsdasd
- 🎃 dsdsdsdsdsddfsgdgasd
- 🍺 jyukyuiyuiyuigkasd
- 🍥 fsdfgdsgsdgdgadsa
- ✨ xcvxcvxcvxcvdasdaasd
- 🍰 dazdsxasxsaxsaasdsa
- 🚨 gdfgdshdfhfhygjtyu
一、观察者模式介绍
观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。
“观察”不是“直接调用”,实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。不管是观察者“观察”对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
观察者模式中存在两种角色:
- 观察者: 内部包含被观察者对象,当被观察者对象的状态发⽣变化时,更新⾃⼰的状态。(接收通知更新状态)
- 被观察者(主题): 内部包含了所有观察者对象,当状态发⽣变化时通知所有的观察者更新⾃⼰的状态。(发送通知)
二、使用观察者模式的场景
- 当⼀个对象的改变需要同时改变其他对象,且不知道具体有多少对象有待改变时,应该考虑使用观察者模式;
- ⼀个抽象模型有两个方面,其中⼀方面依赖于另⼀方面,这时可以用观察者模式将这两者封装在独立的对象中使它们各自独立地改变和复用。
应用场景
世界时钟程序
世界时钟程序,有多个图形时钟去显示比如北京时区,巴黎时区,等等。如果设置一个北京时间,那么其他时钟图形都需要根据时差更新时区时间。
温度程序图形界面
一个温度程序,在温度条件改变时,需要更新显示图形来呈现。
三、发布-订阅模式
其实24种基本的设计模式中并没有发布订阅模式,也有说他只是观察者模式的一个别称。但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。
发布订阅模式也是一种一对多的依赖关系,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件或消息通道,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。消息的发布者将消息发布到通道中,订阅者从通道中订阅消息。
当存在一个复杂的消息通信网络,多个发布者和多个订阅者之间需要进行灵活的消息交互时,可以使用发布-订阅模式。例如,分布式系统中的事件通知、消息队列等情况。
举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。
发布订阅模式中,有以下角色:
消息通道(Message Channel): 用于发布者发布消息和订阅者订阅消息的中介。
发布者(Publisher): 负责发布消息到消息通道。
订阅者(Subscriber): 订阅感兴趣的消息类型,并从消息通道中接收相应的消息。
四、观察者模式和发布订阅模式有什么区别?
观察者模式(Observer Pattern)和发布-订阅模式(Publish-Subscribe Pattern)都是用于处理对象之间的一对多依赖关系,但它们在实现方式和应用场景上有一些异同。
观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。
观察者模式,在目标和观察者之间是没有事件通道的。一方面,观察者要想订阅目标事件,由于没有事件通道,因此必须将自己添加到目标(Subject) 中进行管理;另一方面,目标在触发事件的时候,也无法将通知操作(notify) 委托给事件通道,因此只能亲自去通知所有的观察者。
发布订阅模式,相比观察者模式多了个事件通道,事件通道作为调度中心,统一由调度中心进行处理,管理事件的订阅和发布工作,订阅者和发布者互不干扰,彻底隔绝了发布者和订阅者之间的依赖,即订阅者在订阅事件的时候,只关注事件本身,而不关心谁会发布这个事件。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。
异同点:
实现方式: 观察者模式通常是面向对象的,主题和观察者之间直接交互。而发布-订阅模式使用中介(消息通道)来进行消息的发布和订阅,发布者和订阅者之间没有直接的耦合关系。
通信方式: 观察者模式中主题主动通知观察者,而发布-订阅模式中发布者和订阅者之间通过消息通道进行通信。
灵活性: 发布-订阅模式更具有灵活性,可以支持多对多的关系,而观察者模式通常是一对多的关系。
五、观察者模式优缺点
优点:
开闭原则:无需修改发布者的代码就能够引入新的订阅者
可以在运行时建立对象之间的联系
依赖倒置:让耦合的双方都依赖于抽象,而不是依赖于具体
缺点:
过多的更新操作:如果观察者很多,而且每个观察者对主题的状态变化都做出相应的反应,可能会导致系统的性能下降
可能引起循环依赖: 如果观察者之间存在相互依赖,可能导致循环更新,从而影响系统的稳定性和可维护性。
六、代码示例
被观察者(主题)
// 主题类
class Subject
{
public:void addObserver(Observer *obser, int msgid){// map添加数据的方法1_subMap[msgid].push_back(obser);/*** 当_subMap[msgid]不存在时等价于* list<Observer*> mylist;* mylist.push_back(obser)* _subMap[msgid] = mylist */// map添加数据的方法2:/*auto it = _subMap.find(msgid); //if (it != _subMap.end()){it->second.push_back(obser);}else{list<Observer*> lis;lis.push_back(obser);_subMap.insert({ msgid,lis });}*/}// 主题检测发生改变,通知相应的观察者对象处理事件void dispatch(int msgid){auto it = _subMap.find(msgid);if (it != _subMap.end()){for (Observer *pObser : it->second){pObser->handle(msgid);}}}private:unordered_map<int, list<Observer *>> _subMap;
};
观察者
class Observer
{
public:// 处理消息的接口virtual void handle(int msgid) = 0;
};// 第一个观察者实例
class Observer1 : public Observer
{public:void handle(int msgid){switch (msgid){case 1:cout << "Observer1 recv 1 msg!" << endl;break;case 2:cout << "Observer1 recv 2 msg!" << endl;break;default:cout << "Observer1 recv unknow msg!" << endl;break;}}
};//第二个观察者实例
class Observer2 :public Observer
{public:void handle(int msgid){switch (msgid){case 1:cout << "Observer2 recv 1 msg!" << endl;break;case 3:cout << "Observer2 recv 3 msg!" << endl;break;default:cout << "Observer2 recv unknow msg!" << endl;break;}}
};//第三个观察者实例
class Observer3 :public Observer
{public:void handle(int msgid){switch (msgid){case 2:cout << "Observer3 recv 2 msg!" << endl;break;case 3:cout << "Observer3 recv 3 msg!" << endl;break;default:cout << "Observer3 recv unknow msg!" << endl;break;}}
};
main函数
int main()
{cout << "----------------begain------------------" << endl;Subject subject;Observer* p1 = new Observer1();Observer* p2 = new Observer2();Observer* p3 = new Observer3();subject.addObserver(p1, 1);subject.addObserver(p1, 2);subject.addObserver(p2, 2);subject.addObserver(p3, 1);subject.addObserver(p3, 3);int msgid = 0;for (;;){cout << "输入消息id:";cin >> msgid;if (msgid == -1)break;subject.dispatch(msgid);}cout << "----------------end------------------" << endl;return EXIT_SUCCESS;
}
七、总结
以上就是今天要讲的内容,后续会有更多内容。
八、参考资料
版权声明:本文参考了其他资料和CSDN博主的文章,遵循CC 4.0 BY-SA版权协议,现附上原文出处链接及本声明。
- https://blog.csdn.net/bandaoyu/article/details/83385482
- https://blog.csdn.net/m0_56069910/article/details/136642360
- https://blog.csdn.net/hf872914334/article/details/88899326
- https://blog.csdn.net/m0_56069910/article/details/136642360
- https://blog.csdn.net/linux_wgl/article/details/50178539
相关文章:
C++_设计模式\_观察者模式(Observer Pattern)
👋 Hi, I’m liubo👀 I’m interested in harmony🌱 I’m currently learning harmony💞️ I’m looking to collaborate on …📫 How to reach me …📇 sssssdsdsdsdsdsdasd🎃 dsdsdsdsdsddfsg…...
安卓手机如何改ip地址教程
对于安卓手机用户而言,ip修改用在电商、跨境电商、游戏搬砖、社交软件这些需要开多个账号的项目。因为多个设备或账号又不能在同一ip网络下,所以修改手机的IP地址防检测成为一个必要的操作。以下是在安卓手机上更改IP地址的多种方法及详细步骤࿰…...
从Shell到域控:内网渗透中定位域控制器的8种核心方法
在内网渗透中,定位域控制器(Domain Controller, DC)是攻防对抗的关键环节。本文结合实战经验与工具技术,总结出8种从Shell快速发现域控主机的方法,涵盖命令探测、网络扫描、日志分析等维度,助你系统…...
PHP腾讯云人脸核身获取Access Token
参考腾讯云官方文档: 人脸核身 获取 Access Token_腾讯云 public function getAccessToken(){$data [appId > , //WBappid,https://cloud.tencent.com/document/product/1007/49634secret > ,grant_type > client_credential, //授权类型version > 1…...
Kotlin 集合过滤全指南:all、any、filter 及高级用法
在 Kotlin 中,集合过滤是数据处理的核心操作之一。无论是简单的条件筛选,还是复杂的多条件组合,Kotlin 都提供了丰富的 API。本文将详细介绍 filter、all、any、none 等操作符的用法,并展示如何在实际开发中灵活运用它们。 1. 基础…...
解决6栈6层码头集装箱堆栈翻箱最优解问题
‘’’ con 1 origin_stack = [ [4, 4, 1, 0, 0, 0], # 第一栈 [4, 3, 2, 1, 0, 0], # 第二栈 [4, 2, 2, 1, 0, 0], # 第三栈 [3, 3, 3, 1, 0, 0], # 第四栈 [3, 4, 2, 1, 0, 0], # 第五栈 [4, 2, 3, 2, 0, 0] # 第六栈 ] con 2 origin_stack = [ [4, 4, 3, 0, 0, 0], # 第一栈…...
flutter app实现分辨率自适应的图片资源加载
在 Flutter 中,为了实现分辨率自适应的图片资源加载,确实需要遵循特定的目录结构和命名规则。这种机制允许 AssetImage 根据设备的 设备像素比(Device Pixel Ratio, DPR) 自动选择最合适的图片资源。以下是详细的说明和实现步骤&a…...
软件测试之测试数据生成(Excel版)
这是Excel生成测试数据的函数使用 1.时间 1.1.时间 例生成2022-05-01之前一年内任意时间点: =TEXT("2022-05-01"-RAND()-RANDBETWEEN(1,365),"yyyy-mm-dd hh:mm:ss")1.2.年月日 yyyy-mm-dd 以当前时间生成10年的日期 =TEXT(NOW()-RAND()-RANDBETWE…...
(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)
目录 演示视频: 源代码 main.c LCD1602.c LCD1602.h AT24C02.c AT24C02.h Key.c Key.h I2C.c I2C.h Delay.c Delay.h 代码解析与教程: Dealy模块 LCD1602模块 Key模块 I2C总线模块 AT24C02模块 /E2PROM模块 main模块 演示视频: &…...
STL简介 + string【上】
一 . STL简介 1.1 什么是STL STL(standard template libaray - 标准模板库) : 是C标准库的重要组成部分 , 不仅是一个可复用的组件库 , 而且是一个包罗 数据结构 与 算法 的软件框架 。 注意 : 是标准库的一部分 ÿ…...
【Bluedroid】A2DP Sink播放流程源码分析(二)
接上一篇继续分析:【Bluedroid】A2DP Sink播放流程源码分析(一)_安卓a2dp sink播放流程-CSDN博客 AVDTP接收端(Sink)流事件处理 bta_av_sink_data_cback 是 Bluedroid 中 A2DP Sink 角色的 AVDTP 数据回调函数,负责处理接收端的音频数据事件,将底层接收到的音频数据传递…...
redis利用备忘录
fofa: icon_hash"864611937" 防护: redis的安全设置:设置完毕,需要重加载配置文件启动redis 1.绑定内网ip地址进行访问 2. requirepass设置redis密码 3.保护模式开启protected-mode开启(默认开启) 4.最好把…...
SAP系统中MD01与MD02区别
知识点普及-MD01与MD02区别 1、从日常业务中,我们都容易知道MD01是运行全部物料,MD02是运行单个物料 2、在做配置测试中,也出现过MD02可以跑出物料,但是MD01跑不出的情况。 3、MD01与MD02的差异: 3.1、只要在物料主数…...
企业官网nodejs mySQL数据库安装及使用
以下是企业官网的MySQL数据库设计、本地安装指南,以及基于Node.js的增删改查(CRUD)实现方案: 一、MySQL数据库设计(企业官网基础表) 1. 核心表结构 -- 1. 用户表(管理员) CREATE T…...
Spring Boot自动配置原理深度解析:从条件注解到spring.factories
大家好!今天我们来深入探讨Spring Boot最神奇的特性之一——自动配置(Auto-configuration)。这个功能让Spring Boot如此受欢迎,因为它大大简化了我们的开发工作。让我们一起来揭开它的神秘面纱吧!👀 🌟 什么是自动配置…...
ubuntu学习day3
3 编译与调试 3.1 gcc/g编译器 当我们进行编译的时候,要使用一系列的工具,我们称之为工具链。SDK就是编译工具链的简写,我们所使用的是gcc系列编译工具链。使用-v参数来查看gcc的版本,从而确定某些语法特性是否可用,…...
C++数据结构与二叉树详解
前言: 在C编程的世界里,数据结构是构建高效程序的基石,而二叉树则是其中最优雅且应用广泛的数据结构之一。本文将带你深入理解二叉树的本质、实现与应用,助你在算法设计中游刃有余。 一、二叉树的基本概念 1. 什么是二叉树 二叉树…...
论文阅读:2023 arxiv Safe RLHF: Safe Reinforcement Learning from Human Feedback
总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 Safe RLHF: Safe Reinforcement Learning from Human Feedback https://arxiv.org/pdf/2310.12773 https://github.com/PKU-Alignment/safe-rlhf 速览 研究动机ÿ…...
C++11中的std::condition_variable
一、什么是条件变量? std::condition_variable 是C11标准库中提供的线程同步工具,用于在多线程环境中实现“等待-通知”机制。它的核心作用是让线程能够高效地等待某个条件成立,避免“忙等待”对CPU资源的浪费。 条件变量必须与std::mutex配…...
6.8.最小生成树
一.复习: 1.生成树: 对于一个连通的无向图,假设图中有n个顶点,如果能找到一个符合以下要求的子图: 子图中包含图中所有的顶点,同时各个顶点保持连通, 而且子图的边的数量只有n-1条࿰…...
QT中栅格模式探索
1、Qt中选择了栅格模式,如下图所示: 2、在进行整个大的UI界面布局时,需了解每个控件所需要选择的属性sizePolicy。 sizePolicy包含如下几种选择: 3、举个例子:此时整个UI界面,我采用了栅格模式…...
SLAM | 激光SLAM中的退化问题
在激光SLAM中,判断退化环境的核心是通过数学建模分析环境特征对位姿估计的约束能力。除了LOAM中提出的退化因子D外,还存在多种基于表达式和阈值设定的方法。以下是几种典型方法及其实现原理: 1. 协方差矩阵特征值分析 原理:通过分析点云协方差矩阵的特征值分布,判断环境中…...
C++入门基础:命名空间,缺省参数,函数重载,输入输出
命名空间: C语言是基于C语言的,融入了面向对象编程思想,有了很多有用的库,所以接下来我们将学习C如何优化C语言的不足的。 在C/C语言实践中,在全局作用域中变量,函数,类会有很多,这…...
tomcat 的安装与启动
文章目录 tomcat 服务器安装启动本地Tomcat服务器 tomcat 服务器安装 https://tomcat.apache.org/下载 Tomcat 10.0.X 启动本地Tomcat服务器 进入 Tomcat 的 bin...
C 语言中经典的数据结构
在 C 语言中,经典的数据结构通常包括以下几种,每种都有其特定的应用场景和实现方式: 1. 数组(Array) 定义:连续内存空间存储相同类型的数据。 特点:随机访问快(O(1))&am…...
算法-堆+单调栈
堆 首先堆在我们的Java中我们的是一个优先队列类 PriorityQueue 然后我们要弄最大堆和最小堆 最大堆: PriorityQueue<Integer> pq new PriorityQueue<Integer>((a, b) -> b - a); 最小堆: PriorityQueue<Integer> pq new P…...
物联网平台管理系统
物联网平台管理系统概述 物联网平台管理系统是物联网架构中的核心枢纽,承担着承上启下的关键作用。它向下连接各类物联网设备,实现设备的接入、管理与控制;向上为应用开发提供统一的数据接口和共性模块工具,支撑起各种丰富多彩的…...
STM32CubeMX-H7-15-SPI通信协议读写W25Q64
前言 SPI(Serial Peripheral Interface)通信协议是一种高速、全双工、同步的串行通信协议 本篇文章就使用W25Q64模块来学习SPI,包括软件SPI代码的编写,硬件SPI,中断SPI和DMASPI SPI的应用场景和模块 !这里是抄AI的&a…...
【软考】论devops在企业信息系统开发中的应用
摘要: 随着互联网的不断发展,各行各业都在建设自己的企业信息系统,而随着业务的不断升级和复杂化,系统的更新迭代速度越来越快,系统也越来越复杂。对于信息系统开发者,架构师,管理者,…...
生物化学笔记:医学免疫学原理22 肿瘤及肿瘤治疗
肿瘤及肿瘤治疗 免疫疗法 CAR-T细胞介绍...
