C++之观察者模式(发布-订阅)
目录
模式简介
介绍
优点
缺点
代码实现
场景说明
实现代码
运行结果
模式简介
观察者模式(Observer Pattern),也叫我们熟知的发布-订阅模式。
它是一种行为型模式。
介绍
观察者模式主要关注的是对象的一对多的关系,
也就是多个对象依赖于一个对象,当该对象的状态发生改变时,其他对象都能够收到相应的通知
意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。主要解决:
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。如何解决:
使用面向对象技术,可以将这种关系弱化。
优点
- 观察者和被观察者是抽象耦合的;
- 建立了一套触发机制。
缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,通知所有的观察者需要花费很长的时间;
- 如果在观察者和被观察者目标之间有循环依赖的话,观察目标会触发他们之间的循环调用,可能会导致系统崩溃;
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅是知道观察目标发生了变化。
代码实现
场景说明
我们现在有三个观察者和三种消息,这三个观察者分别对不同的消息感兴趣
我们实现的话,可以简单的设置三个观察者,一个主题类(被观察者)。
这三个观察者可以设置自己喜欢的、感兴趣的消息类型(1、2、3)。
他们处理收到的消息就是打印一下自己收到了什么消息。
具体实现如下
实现代码
/*observer1 observer2 observer3Subject (主题)主题更改,应该及时通知相应的观察者,去处理相应的事件
*/
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 unkonw msg!" << endl;break;}}
};
//第二个观察者实例
class Observer2 : public Observer
{
public:void handle(int msgid){switch (msgid){case 2:cout << "Observer2 recv 2 msg" << endl;break;default:cout << "Observer2 recv unkonw msg!" << endl;break;}}
};
//第三个观察者实例
class Observer3 : public Observer
{
public:void handle(int msgid){switch (msgid){case 1:cout << "Observer3 recv 1 msg" << endl;break;case 3:cout << "Observer3 recv 3 msg" << endl;break;default:cout << "Observer3 recv unkonw msg!" << endl;break;}}
};//主题类
class Subject
{
public://给主题增加观察者对象void addObserver(Observer* obser,int msgid){_subMap[msgid].push_back(obser);}//主题检测发生改变,通知相应的观察者对象处理事件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;
};
我们可以看到主题类(Subject)的数据成员是一个unordered_map。使用这个是因为我们不需要数据是有序的,为了提高增删查的速率,使用了无序map。
使用map的好处是,它作为一个键值对,可以存储我们想要的数据类型:(消息类型,订阅此消息类型的观察者们)。
并且,在主题类(Subject)的成员方法addObserver中,我们使用了一个中括号运算符([])重载的特性:
如果当前容器中存有相应的msgid键的话,就直接添加对应的值(Obser);
如果当前容器中没有相应的msgid键的话,就直接添加该键,并且添加一个默认的值。
运行结果
我们使用如下的代码:
void main()
{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:" << endl;cin >> msgid;if (msgid == -1)break;subject.dispatch(msgid);//发起通知}
}
运行结果如下

相关文章:
C++之观察者模式(发布-订阅)
目录 模式简介 介绍 优点 缺点 代码实现 场景说明 实现代码 运行结果 模式简介 观察者模式(Observer Pattern),也叫我们熟知的发布-订阅模式。 它是一种行为型模式。 介绍 观察者模式主要关注的是对象的一对多的关系, …...
无头单链表,有完整测试程序
🍟无头单链表 👻无头单链表的所有结点都存储有效信息 👻无头单链表相对带头单链表,在有些涉及更改头节点的函数上需要传二级指针 🍟头文件list.h #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #includ…...
2023年第四届“华数杯”数学建模思路 - 案例:FPTree-频繁模式树算法
## 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法,就是频繁模式树算法,他与Apriori算法一样也是用来挖掘频繁项集的,…...
MySQL做分布式锁
分布式锁mysql实现方式 方式1:唯一索引 创建锁表,内部存在字段表示资源名及资源描述,同一资源名使用数据库唯一性限制。多个进程同时往数据库锁表中写入对某个资源的占有记录,当某个进程成功写入时则表示其获取锁成功其他进程由于…...
Python学习笔记:变量类型、字符串基本操作
1.注释 单行注释 # 单行注释 多行注释 """ 多行注释 """2.变量类型 # 基本变量类型 a 1 # integer b 1.5 # float c string # String d "string" # string e False # boolean # list\tuple\dictionar…...
JVM的组件、自动垃圾回收的工作原理、分代垃圾回收过程、可用的垃圾回收器类型
详细画的jvm模型图 https://www.processon.com/diagraming/64c8aa11c07d99075d934311 官方网址 https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html 相关概念 年轻代是所有新对象被分配和老化的地方。当年轻代填满时,这会导致m…...
【elementui】解决el-select组件失去焦点blur事件每次获取的是上一次选中值的问题
目录 【问题描述】 【问题摘要】 【分析问题】 【完整Test代码】 【封装自定义指令】 ↑↑↑↑↑↑↑↑↑↑↑↑ 不想看解决问题过程的可点击上方【封装自定义指令】目录直接跳转获取结果即可~~~ 【问题描述】 一位朋友遇到这么一个开发场景:在表格里面嵌入el-…...
通过了PMP考试,还有什么证书值得考?
自从7月24号公布了PMP成绩后,不少伙伴私信小编:通过PMP后还有哪些证书可以提升自己?一来是多份高含金量的证书可以多点竞争力,二来是加持自己的职业发展!今天小编就来给大家捋一捋! 一.NPDP认证 2016 年 4…...
页面技术基础-html
页面技术基础-html 环境准备:在JDBC中项目上完成代码定义 1. 新建一个 Module:filr->右键 -》Module -》Java-》next->名字(html_day1)->finish 2. 在 Moudle上右键-》第二个选项:add framework .. -> 选择JavaEE下第一个选项 Web Apllicat…...
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28‘ not found
某项目中,我要给别人封装一个深度学习算法的SDK接口,运行在RK3588平台上,然后客户给我的交叉编译工具链是 然后我用他们给我的交叉编译工具链报下面的错误: aarch64-buildroot-linux-gnu-gcc --version /data/chw/aarch64/bin/cca…...
解决SVN或GIT忽略提交文件的问题
背景 使用IDEA 的SVN插件提交文件是总是会提交一些不需要提交的文件; 我们可以通过一些简单设置忽略这些文件。 git 在项目根目录新建文本文件,修改后缀为.gitignore 文件中添加内容 *.iml .project .gradle/ .idea/ target/ build/ .vscode/ .settings/ .facto…...
Django框架之路由用法
简介 路由简单的来说就是根据用户请求的 URL 链接来判断对应的处理程序,并返回处理结果,也就是 URL 与 Django 的视图建立映射关系。 Django 路由在 urls.py 配置,urls.py 中的每一条配置对应相应的处理方法。 Django 不同版本 urls.py 配…...
回文链表 LeetCode热题100
题目 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 思路 利用快慢指针找到链表中间节点,反转后半段链表。前半段从头节点开始与后半段比较。 注意当链表节点…...
如何在群晖NAS中使用cpolar内网穿透
如何在群晖nas中使用cpolar内网穿透 文章目录 如何在群晖nas中使用cpolar内网穿透 今天,我们来为大家介绍,如何在群晖系统中,使用图形化界面的cpolar。 cpolar经过图形化改造后,使用方法已经简便了很多,基本与其他应用…...
无头单向不循环链表和带头双向循环链表的创建
Lei宝啊:个人主页 愿所有美好不期而遇 前言: 接下来我们将会了解最基础的链表--->单链表 以及最方便也是最爽的链表--->带头双向循环链表。 若有看不懂之处,可画图或者借鉴这里:反转单链表,对于数据结构而言&am…...
超简单的fastapi链接websocket用例
main.py from typing import Listfrom fastapi import FastAPI, WebSocket, WebSocketDisconnectapp FastAPI()class ConnectionManager:def __init__(self):# 存放激活的ws连接对象self.active_connections: List[WebSocket] []async def connect(self, ws: WebSocket):# 等…...
MySQL详解
目录 一、MySQL 概述二、MySQL 安装和配置三、MySQL 基础语法四、MySQL 高级语法五、MySQL 性能优化六、MySQL 应用场景和实例七、MySQL 开发工具和插件八、MySQL 学习资源和社区 一、MySQL 概述 MySQL 是一种开源的关系型数据库管理系统,最初由瑞典的 MySQL AB 公…...
Vue [Day2]
指令修饰符 v-model.trim v-model.number 事件名.stop click.stop 事件名.prevent keyup.enter <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-w…...
【前端|Javascript第1篇】一文搞懂Javascript的基本语法
欢迎来到JavaScript的奇妙世界!作为前端开发的基石,JavaScript为网页增色不少,赋予了静态页面活力与交互性。如果你是一名前端小白,对编程一无所知,或者只是听说过JavaScript却从未涉足过,那么你来对了地方…...
【Linux命令200例】cp用于复制文件和目录(常用)
🏆作者简介,黑夜开发者,全栈领域新星创作者✌,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆本文已收录于专栏:Linux命令大全。 🏆本专栏我们会通过具体的系统的命令讲解加上鲜…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
使用python进行图像处理—图像滤波(5)
图像滤波是图像处理中最基本和最重要的操作之一。它的目的是在空间域上修改图像的像素值,以达到平滑(去噪)、锐化、边缘检测等效果。滤波通常通过卷积操作实现。 5.1卷积(Convolution)原理 卷积是滤波的核心。它是一种数学运算,…...
基于小程序老人监护管理系统源码数据库文档
摘 要 近年来,随着我国人口老龄化问题日益严重,独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长,随之而来的是日益突出的老年人问题,尤其是老年人的健康问题,尤其是老年人产生健康问题后&…...
