C++ 观察者模式
观察者模式(Observer Pattern)是一种行为设计模式,用于在对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,它的所有依赖对象都会得到通知并自动更新。

在观察者模式中,主题和观察者之间是松耦合的,主题并不知道观察者的具体实现,只依赖于观察者接口。这种松耦合的关系使得主题和观察者能够独立变化,而不会相互影响。
#include <iostream>
#include <string>
#include <unordered_map>
#include <bits/stdc++.h>
#include <list>using namespace std;
/*
* 行为型模式:主要关注的是对象之间的通信
观察者-监听者模式 (发布-订阅模式) 设计模式:主要关注的对象是一对多的关系,
也就是说多个对象都依赖与这一个对象,当这个对象的状态发生改变时,其他对象都能够
接收到相应的通知。
*/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 2:cout << "Observer2 recv 2 msg!" << endl;break;default:cout << "Observer2 recv unknow 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 unknow msg! " << endl;break;}}
};class Subject
{
public: //主题增加相应观察者对象void addObserver(Observer* obser, int msgid){_subMap[msgid].push_back(obser);/*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;
};int 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: ";cin >> msgid;if (msgid == -1) break;subject.dispatch(msgid);}return 0;
}
输入消息id: 2
Observer1 recv 2 msg!
Observer2 recv 2 msg!输入消息id: 1
Observer1 recv 1 msg!
Observer3 recv 1 msg!输入消息id: 3
Observer3 recv 3 msg!
主要解决的是对象与对象之间的依赖关系,多个对象依赖于一个对象,该对象主要负责检测我们消息发没发生状态改变,有改变了就要通知相应的观察者。
这里涉及多对象内存开辟问题,需要使用智能指针去优化:
#include<iostream>
#include<unordered_map>
#include<list>
#include<bits/stdc++.h>
#include<memory>class Observer
{
public:virtual void handle(int msgid) = 0; //纯虚函数没有具体实现
};class Observer1 : public Observer
{
public:void handle(int msgid){switch (msgid){case 1:std::cout << "Observer 1 recv 1 msg!" << std::endl;break;case 2:std::cout << "Observer 1 recv 2 msg!" << std::endl;break;default:std::cout << "Observer 1 recv unknow msg!" << std::endl;break;}}
};class Observer2 : public Observer
{
public:void handle(int msgid){switch (msgid){case 2:std::cout << "Observer 2 recv 2 msg!" << std::endl;break;default:std::cout << "Observer 2 recv unknow msg! " << std::endl;break;}}
};class Observer3 : public Observer
{
public:void handle(int msgid){switch (msgid){case 1:std::cout << "Obersever 3 recv 1 msg!" << std::endl;break;case 3:std::cout << "Obersever 3 recv 3 msg!" << std::endl;break;default:std::cout << "Observer 3 recv unknow msg! " << std::endl;break;}}
};class Subject
{
public:void addObserver(std::weak_ptr<Observer> obser, int msgid){_subMap[msgid].push_back(obser);}void dispatch(int msgid){auto it = _subMap.find(msgid);if (it != _subMap.end()){for (auto it1 = it->second.begin(); it1 != it->second.end(); ++it1){ // 与强指针绑定的弱指针,通过lock函数提升为强指针,可以避免循环引用问题,同时判断所绑定的对象是否被销毁std::shared_ptr<Observer>tmp = it1->lock();if (tmp) {tmp->handle(msgid);}}}}
private:std::unordered_map<int, std::list<std::weak_ptr<Observer>> > _subMap;
};int main()
{Subject subject;std::shared_ptr<Observer>p1(new Observer1);std::shared_ptr<Observer>p2(new Observer2);std::shared_ptr<Observer>p3(new Observer3);// shared_ptr赋值给weak_ptr,绑定subject.addObserver(p1, 1);subject.addObserver(p1, 2);subject.addObserver(p2, 2);subject.addObserver(p3, 1);subject.addObserver(p3, 3);int msgid = 0;for (;;){std::cout << " 输入消息id: ";std::cin >> msgid;if (msgid == -1) break;subject.dispatch(msgid);}return 0;
}
重点就是这里,一开始用弱指针去绑定一些对象subject.addObserver(p1, 1);,通过弱指针提升为强指针,来判断所绑定的对象是否被销毁std::shared_ptr<Observer>tmp = it1->lock();(muduo项目中,channel与TcpConnection对象绑定):
std::shared_ptr<Observer>tmp = it1->lock();
if (tmp) {tmp->handle(msgid);
}
相关文章:
C++ 观察者模式
观察者模式(Observer Pattern)是一种行为设计模式,用于在对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,它的所有依赖对象都会得到通知并自动更新。 在观察者模式中,主题和观察者之间是松耦合…...
基于pytorch的手写数字识别-训练+使用
import pandas as pd import numpy as np import torch import matplotlib import matplotlib.pyplot as plt from torch.utils.data import TensorDataset, DataLoadermatplotlib.use(tkAgg)# 设置图形配置 config {"font.family": serif,"mathtext.fontset&q…...
SpringBoot接收前端传递参数
1)URL 参数 参数直接 拼接在URL的后面,使用 ? 进行分隔,多个参数之间用 & 符号分隔。例如:http://localhost:8080/user?namezhangsan&id1后端接收(在Controller方法的参数列表中使用 RequestParam 注解&…...
【LeetCode周赛】第 418 场
3309. 连接二进制表示可形成的最大数值 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接 数组 nums 中所有元素的 二进制表示 ,请你返回可以由这种方法形成的 最大 数值。 注意 任何数字的二进制表示 不含 前导零 思路:暴力枚举 class Soluti…...
Android学习7 -- NDK2 -- 几个例子
学习 Android 的 NDK(Native Development Kit)可以帮助你用 C/C 来开发高性能的 Android 应用,特别适合对性能要求较高的任务,如音视频处理、游戏开发和硬件驱动等。下面是学习 NDK 的建议步骤和具体例子: ### 1. **准…...
问:说说JVM不同版本的变化和差异?
在Java程序的执行过程中,Java虚拟机(JVM)扮演着至关重要的角色。它不仅负责解释和执行Java字节码,还管理着程序运行时的内存。根据JVM规范,JVM将其所管理的内存划分为多个不同的数据区域,包括程序计数器、J…...
计算机毕业设计 基于Python的社交音乐分享平台的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...
51单片机的水位检测系统【proteus仿真+程序+报告+原理图+演示视频】
1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块水位传感器继电器LED、按键和蜂鸣器等模块构成。适用于水位监测、水位控制、水位检测相似项目。 可实现功能: 1、LCD1602实时显示水位高度 2、水位传感器采集水位高度 3、按键可设置水位的下限 4、按键可手动加…...
Python和R及Julia妊娠相关疾病生物剖析算法
🎯要点 算法使用了矢量投影、现代优化线性代数、空间分区技术和大数据编程利用相应向量空间中标量积和欧几里得距离的紧密关系来计算使用妊娠相关疾病(先兆子痫)、健康妊娠和癌症测试算法模型使用相关性投影利用相关性和欧几里得距离之间的关…...
Web安全 - 重放攻击(Replay Attack)
文章目录 OWASP 2023 TOP 10导图1. 概述2. 重放攻击的原理攻击步骤 3. 常见的重放攻击场景4. 防御重放攻击的技术措施4.1 使用时效性验证(Time-Based Tokens)4.2 单次令牌机制(Nonce)4.3 TLS/SSL 协议4.4 HMAC(哈希消息…...
Python项目文档生成常用工具对比
写在前面: 通过阅读本片文章,你将了解:主流的Python项目文档生成工具(Sphinx,MkDocs,pydoc,Pdoc)简介及对比,本文档不涉及相关工具的使用。 概述 近期,由于…...
教育领域的技术突破:SpringBoot系统实现
2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…...
RabbitMQ入门3—virtual host参数详解
在 RabbitMQ 中,创建 Virtual Host 时会涉及到一些参数配置,比如 tags 和 Default Queue Type。下面是对这两个参数的详细解释: 1. Tags Tags 是 Virtual Host 的标记,用来为 Virtual Host 添加元数据,帮助你管理和组…...
【Nacos入门到实战十四】Nacos配置管理:集群部署与高可用策略
个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] 📱…...
UE5+ChatGPT实现3D AI虚拟人综合实战
第11章 综合实战:UE5ChatGPT实现3D AI虚拟人 通过结合Unreal Engine 5(UE5)的强大渲染能力和ChatGPT的自然语言处理能力,我们可以实现一个高度交互性的AI虚拟人。本文将详细介绍如何在UE5中安装必要的插件,配置OpenAI…...
[图形学]smallpt代码详解(2)
一、简介 本文紧接在[图形学]smallpt代码详解(1)之后,继续详细讲解smallpt中的代码,包括自定义函数(第41到47行)和递归路径跟踪函数(第48到74行)部分。 二、smallpt代码详解 1.自…...
vmstat命令:系统性能监控
一、命令简介 vmstat 是一种在类 Unix 系统上常用的性能监控工具,它可以报告虚拟内存统计信息,包括进程、内存、分页、块 IO、陷阱(中断)和 CPU 活动等。 二、命令参数 2.1 命令格式 vmstat [选项] [ 延迟 [次数] ]2…...
linux部署NFS和autofs自动挂载
目录 (一)NFS: 1. 什么是NFS 2. NFS守护进程 3. RPC服务 4. 原理 5. 部署 5.1 安装NFS服务 5.2 配置防火墙 5.3 创建服务端共享目录 5.4 修改服务端配置文件 (1). /etc/exports (2). nfs.conf 5.5 启动nfs并加入自启 5.6 客户端…...
WPF RadioButton 绑定boolean值
<RadioButtonMargin"5"Content"替换"IsChecked"{Binding CorrectionOption.ReCorrectionMode}" /> <RadioButtonMargin"5"Content"平均"IsChecked"{Binding CorrectionOption.ReCorrectionMode, Converter{St…...
2024 ciscn WP
一、MISC 1.火锅链观光打卡 打开后连接自己的钱包,然后点击开始游戏,答题八次后点击获取NFT,得到有flag的图片 没什么多说的,知识问答题 兑换 NFT Flag{y0u_ar3_hotpot_K1ng} 2.Power Trajectory Diagram 方法1: 使用p…...
手把手教你部署DeepSeek-R1:纯CPU环境搭建逻辑推理AI全攻略
手把手教你部署DeepSeek-R1:纯CPU环境搭建逻辑推理AI全攻略 1. 从零开始:为什么你需要一个本地推理引擎 想象一下这个场景:你正在处理一份包含敏感数据的文档,需要AI帮你分析逻辑关系,但公司规定数据不能上传到云端。…...
ModelScope与Hugging Face中文API调用全攻略:从安装到实战代码解析
ModelScope与Hugging Face中文API调用全攻略:从安装到实战代码解析 如果你正在寻找一个能够快速上手ModelScope和Hugging Face API的指南,特别是针对中文开发者的实用教程,那么你来对地方了。这两个平台作为当前最受欢迎的AI模型开源社区&…...
OpenClaw+Qwen3-32B自动化办公:会议纪要生成与飞书同步实战
OpenClawQwen3-32B自动化办公:会议纪要生成与飞书同步实战 1. 为什么需要自动化会议纪要 每次开完会最痛苦的事情是什么?对我来说就是整理会议纪要。作为技术负责人,每周要参加5-6个不同主题的会议,会后需要花大量时间回听录音、…...
Python多解释器冷启动优化:从2.1s到87ms的极致压缩术(附可复用的预热调度器)
第一章:Python多解释器冷启动优化:从2.1s到87ms的极致压缩术(附可复用的预热调度器) 在微服务与Serverless场景中,Python多解释器(如PyO3、subinterpreters或进程级隔离)常因模块导入、C扩展初始…...
Claude Code进阶实战:构建MCP驱动的多Agent协同开发流水线
1. 理解MCP驱动的多Agent协同开发 在传统软件开发中,一个工程师往往需要同时承担需求分析、UI设计、编码实现和测试验证等多个角色。这种"全栈式"工作模式虽然灵活,但随着项目复杂度提升,很容易出现专业深度不足、效率下降的问题。…...
DanKoe 视频笔记:数字时代财富创造指南:思想是新石油
在本节课中,我们将探讨在数字时代创造财富的新范式。我们将分析传统投资和房地产的局限性,并揭示“思想”如何成为这个时代最宝贵的、可无限开采的资源。通过理解并构建“数字房地产”,任何人都可以踏上一条全新的致富之路。 概述࿱…...
SSE vs. WebSocket:实时通信技术的深度对比与选型指南
1. 实时通信技术的基本概念 现代Web应用对实时性的需求越来越高,从股票行情更新到在线聊天室,都需要服务器能够快速将数据推送到客户端。在这个领域,SSE(Server-Sent Events)和WebSocket是两种主流技术方案。我第一次接…...
MyBatisPlus SQL解析踩坑记:JSqlParser版本升级的那些事儿
MyBatisPlus SQL解析踩坑记:JSqlParser版本升级的那些事儿 当你在深夜被生产环境的报警短信惊醒,发现原本运行良好的SQL查询突然报出Encountered unexpected token错误时,很可能正遭遇JSqlParser版本升级带来的"惊喜"。作为MyBatis…...
全面解析数据库锁机制:从行锁到死锁的深度剖析
锁是数据库并发控制的核心机制,也是面试中绕不开的高频考点。很多开发者对锁的理解停留在“加锁就行了”,但遇到死锁、锁等待超时、性能骤降等问题时往往束手无策。本文将系统讲解数据库锁的分类、实现原理、锁与事务隔离级别的关系,并结合 M…...
2026年全国青少年信息素养大赛算法应用主题赛(C++赛项初赛模拟题)
2026年全国青少年信息素养大赛算法应用主题赛(C赛项初赛模拟题) 一、单项选择题(共 15 题,每题 5 分) 1. 数组下标与长征物资 题目内容 你需要记录红军某运输队一周(7 天)的粮食消耗量&#x…...
