观察者模式的C++实现示例
核心思想
观察者模式是一种行为型设计模式,定义了对象之间的一对多依赖关系。当一个对象(称为Subject,主题)的状态发生改变时,所有依赖于它的对象(称为Observer,观察者)都会自动收到通知并更新。
**Subject:**维护观察者列表,提供注册、移除观察者的方法,以及通知观察者的功能。
**Observer:**定义一个更新接口,用于在Subject状态改变时接收通知。
观察者模式的核心是解耦:Subject和Observer之间没有直接依赖,Subject只需通知Observer,而不需要知道Observer的具体实现。
使用场景
事件驱动系统:如GUI框架中,按钮点击事件通知多个监听器。
发布-订阅模型:如消息队列、事件总线。
数据与UI同步:如MVC架构中,Model变化时自动更新View。
监控系统:如系统状态变化时通知多个监控服务。
游戏开发:如角色状态变化时通知多个UI组件或AI系统。
解决的问题
紧耦合问题:
在传统设计中,Subject需要直接调用Observer的方法,导致两者紧耦合。观察者模式通过引入Observer接口,使Subject和Observer解耦。
动态更新问题:
当Subject状态变化时,需要手动调用所有依赖对象的更新方法。观察者模式通过notify方法自动通知所有Observer。
可扩展性问题:
新增Observer时,需要修改Subject的代码。观察者模式允许动态注册和移除Observer,无需修改Subject。
示例代码
#include <iostream>
#include <list>
#include <memory>
#include <mutex>// 观察者接口
class Observer {
public:virtual ~Observer() = default;virtual void update(const std::string& message) = 0;
};// 主题基类
class Subject {
protected:std::list<std::weak_ptr<Observer>> observers; // 使用weak_ptr防止循环引用std::mutex mutex;//多线程环境下需要使用
public:// 添加观察者(使用智能指针管理)void attach(const std::shared_ptr<Observer> observer){std::lock_guard<std::mutex> lock(mutex);observers.push_back(observer);}// 移除观察者void detach(const std::shared_ptr<Observer> observer){std::lock_guard<std::mutex> lock(mutex);auto it = observers.begin();while(it != observers.end()){//std::weak_ptr的lock()方法返回对应的std::shared_ptrif(observer == it->lock()){it = observers.erase(it);continue;}it++;}}// 通知所有观察者void notify(const std::string& message){std::lock_guard<std::mutex> lock(mutex);auto it = observers.begin();while (it != observers.end()){//检查观察者是否有效,因为观察者有可能在别的地方被清理了if (!it->expired()){//std::weak_ptr的lock()方法返回对应的std::shared_ptr,只能通过std::shared_ptr操作管理的对象it->lock()->update(message);++it;}else{it = observers.erase(it); // 自动清理失效的观察者}}}
};// 具体主题:新闻发布器
class NewsPublisher : public Subject {
public:void publishNews(const std::string& news){std::cout << "publishNews: " << news << std::endl;notify(news); // 通知所有观察者}
};// 具体观察者1:邮件订阅者
class EmailSubscriber : public Observer
{
public:~EmailSubscriber(){std::cout << "EmailSubscriber destroyed"<< std::endl;}void update(const std::string& message) override{std::cout << "EmailSubscriber recive: " << message << std::endl;}
};// 具体观察者2:短信订阅者
class SMSSubscriber : public Observer
{
public:~SMSSubscriber(){std::cout << "SMSSubscriber destroyed"<< std::endl;}void update(const std::string& message) override{std::cout << "SMSSubscriber recive: " << message << std::endl;}
};int main() {// 创建主题NewsPublisher publisher;// 创建观察者(使用智能指针)auto emailSubscriber = std::make_shared<EmailSubscriber>();auto smsSubscriber = std::make_shared<SMSSubscriber>();// 注册观察者publisher.attach(emailSubscriber);publisher.attach(smsSubscriber);// 发布新闻(通知所有观察者)publisher.publishNews("C++20 has been published!");// 移除一个观察者publisher.detach(smsSubscriber);publisher.publishNews("designe patten meeting");// 测试观察者自动清理{auto tempSubscriber = std::make_shared<EmailSubscriber>();publisher.attach(tempSubscriber);publisher.publishNews("temporary news");} // tempSubscriber离开作用域,自动解除注册publisher.publishNews("only subscriber recived this message.");return 0;
}
运行输出
publishNews: C++20 has been published!
EmailSubscriber recive: C++20 has been published!
SMSSubscriber recive: C++20 has been published!
publishNews: designe patten meeting
EmailSubscriber recive: designe patten meeting
publishNews: temporary news
EmailSubscriber recive: temporary news
EmailSubscriber recive: temporary news
EmailSubscriber destroyed
publishNews: only subscriber recived this message.
EmailSubscriber recive: only subscriber recived this message.
SMSSubscriber destroyed
EmailSubscriber destroyed
相关文章:
观察者模式的C++实现示例
核心思想 观察者模式是一种行为型设计模式,定义了对象之间的一对多依赖关系。当一个对象(称为Subject,主题)的状态发生改变时,所有依赖于它的对象(称为Observer,观察者)都会自动收到…...
爬虫(持续更新ing)
爬虫(持续更新ing) # 网络请求 # url统一资源定位符(如:https://www.baidu.com) # 请求过程:客户端的web浏览器向服务器发起请求 # 请求又分为四部分:请求网址,请求方法(…...
AD学习-最小系统板,双层
第一章 简单电阻容模型的创建 捕捉栅格在摆放器件时,一般设置成 10mil。移动器件时一般设置成100mil。 比如绘制电容的原理图库,直接就是两根线条竖着成电容, 按Tab键进行颜色变更,按shift键拖动会复制一个出来。 …...
自动驾驶---不依赖地图的大模型轨迹预测
1 前言 早期传统自动驾驶方案通常依赖高精地图(HD Map)提供道路结构、车道线、交通规则等信息,可参考博客《自动驾驶---方案从有图迈进无图》,本质上还是存在问题: 数据依赖性高:地图构建成本昂贵…...
【五.LangChain技术与应用】【8.LangChain提示词模板基础:从入门到精通】
早上八点,你端着咖啡打开IDE,老板刚甩来需求:“做个能自动生成产品描述的AI工具”。你自信满满地打开ChatGPT的API文档,结果半小时后对着满屏的"输出结果不稳定"、"格式总出错"抓耳挠腮——这时候你真需要好好认识下LangChain里的提示词模板了。 一、…...
【AGI】智谱开源2025:一场AI技术民主化的革命正在到来
智谱开源2025:一场AI技术民主化的革命正在到来 引言:开源,一场技术平权的革命一、CogView4:中文AI生成的里程碑1. 破解汉字生成的“AI魔咒”2. 开源协议与生态赋能 二、AutoGLM:人机交互的范式跃迁1. 自然语言驱动的跨…...
Markdown HTML 图像语法
插入图片 Markdown 一般来说,直接复制粘贴过来就行了,部分网页/应用可以拖拽,没人会真敲图片的链接吧…… 示例图片: 总架构师,15年工作经验,精通Java编…...
国产化替换案例:CACTER邮件网关为Groupwise系统加固邮件安全防线
电子邮件作为企业信息流转的命脉,承载着商业机密与客户数据。然而,网络攻击手段日益复杂,钓鱼邮件等威胁正快速侵蚀企业安全防线。据《2024年第四季度企业邮箱安全性研究报告》显示,2024年Q4企业邮箱用户遭遇的钓鱼邮件数量激增至…...
Element UI-Select选择器结合树形控件终极版
Element UI Select选择器控件结合树形控件实现单选和多选,并且通过v-model的方式实现节点的双向绑定,封装成vue组件,文件名为electricity-meter-tree.vue,其代码如下: <template><div><el-select:valu…...
《底层逻辑》总结书摘
《底层逻辑》由张羽所著,聚焦于职场与个人发展,深入阐述了定位、结果、学习等十大底层逻辑,旨在帮助读者掌握思考和解决问题的有效方法,提升职场竞争力与个人成就。 核心观点:思维和行动决定命运,格局与价值…...
【Linux】【网络】UDP打洞-->不同子网下的客户端和服务器通信(未成功版)
【Linux】【网络】UDP打洞–>不同子网下的客户端和服务器通信(未成功版) 上次说基于UDP的打洞程序改了五版一直没有成功,要写一下问题所在,但是我后续又查询了一些资料,成功实现了,这次先写一下未成功的…...
【微信小程序】每日心情笔记
个人团队的比赛项目,仅供学习交流使用 一、项目基本介绍 1. 项目简介 一款基于微信小程序的轻量化笔记工具,旨在帮助用户通过记录每日心情和事件,更好地管理情绪和生活。用户可以根据日期和心情分类(如开心、平静、难过等&#…...
PMP项目管理—沟通管理篇—3.监督沟通
文章目录 基本信息4W1HITTO输入工具与技术输出 工作绩效信息和变更请求 基本信息 4W1H what: 确保满足项目及其相关方的信息需求的过程。why: 通过监督沟通过程,来确定规划的沟通工作和沟通活动是否如预期,提高或保持了相关方对项目可交付成果与预计结…...
在Linux中开发OpenGL——检查开发环境对OpenGL ES的支持
由于移动端GPU规模有限,厂商并没有实现完整的OpenGL特性,而是实现了它的子集——OpenGL ES。因此如果需要开发的程序要支持移动端平台,最好使用OpenGL ES开发。 1、 下载支持库、OpenGL ES Demo 1.1、下载PowerVRSDK支持库作为准备ÿ…...
低空经济-飞行数据平台 搭建可行方案
搭建一个飞行数据平台是低空经济中至关重要的一环,它能够实现对飞行器的实时监控、数据分析、路径优化以及安全管理。以下是搭建飞行数据平台的详细步骤和技术方案: 一、平台的核心功能 实时监控: 实时获取飞行器的位置、速度、高度、电池状态等数据。提供可视化界面,展示飞…...
python量化交易——金融数据管理最佳实践——使用qteasy大批量自动拉取金融数据
文章目录 使用数据获取渠道自动填充数据QTEASY数据拉取功能数据拉取接口refill_data_source()数据拉取API的功能特性多渠道拉取数据实现下载流量控制实现错误重试日志记录其他功能 qteasy是一个功能全面且易用的量化交易策略框架, Github地址在这里。使用它&#x…...
为AI聊天工具添加一个知识系统 之136 详细设计之77 通用编程语言 之7
问题 Q1492、针对前面您给出的“AI聊天工具知识系统设计文档”,请就您后面所述“智能进化:认知演进路由驱动知识库持续优化”进行更深入的实现讨论 Q1493、感觉不够完整。下面我们针对您前面给出的“知识系统三层架构详述”逐层给出详细地实现方案。 …...
【CSRF实践】DVWA靶场之CSRF实践
CSRF介绍 CSRF(Cross-site request forgery),中文名叫做“跨站请求伪造”,也被称作“one click attack/session riding”,缩写为“CSRF/XSRF”。在场景中,攻击者会伪造一个请求(通常是一个链接)࿰…...
数据库设计方面如何进行PostgreSQL 17的性能调优?
在数据库设计方面,PostgreSQL 17 的性能调优可以从以下几个方面入手: 表结构设计 选择合适的数据类型:根据数据的实际范围和业务需求,选择占用空间小、查询效率高的数据类型。对于固定长度的字符串,如性别字段&#…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
