观察者模式的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 一般来说,直接复制粘贴过来就行了,部分网页/应用可以拖拽,没人会真敲图片的链接吧…… 示例图片: 
DeepSeek 角色设定与风格控制
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,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 的性能调优可以从以下几个方面入手: 表结构设计 选择合适的数据类型:根据数据的实际范围和业务需求,选择占用空间小、查询效率高的数据类型。对于固定长度的字符串,如性别字段&#…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...

实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...