C++观察者模式代码实例

文章目录

    • C++观察者模式代码实例一
    • C++观察者模式代码实例二

C++观察者模式代码实例一

下面是一个简单的C++观察者模式的实现示例,这里仅给出核心代码框架,完整的工程应包含对应的头文件声明及必要的#include指令等。

// 观察者接口(Observer)
class IObserver {
public:virtual ~IObserver() {}virtual void update(const std::string& message) = 0; // 更新方法
};// 主题接口(Subject)
class ISubject {
public:virtual ~ISubject() {}virtual void registerObserver(IObserver* observer) = 0; // 注册观察者virtual void removeObserver(IObserver* observer) = 0; // 移除观察者virtual void notifyObservers(const std::string& message) = 0; // 通知观察者
};// 具体主题(ConcreteSubject)
class ConcreteSubject : public ISubject {
private:std::vector<IObserver*> observers; // 存储观察者列表public:void registerObserver(IObserver* observer) override {observers.push_back(observer);}void removeObserver(IObserver* observer) override {observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());}void notifyObservers(const std::string& message) override {for (const auto& obs : observers) {obs->update(message);}}// 其他业务逻辑,当有状态改变时调用notifyObservers()void changeState(const std::string& newState) {// 假设这里有某种状态变更逻辑std::string message = "状态已更新至:" + newState;notifyObservers(message);}
};// 具体观察者(ConcreteObserver)
class ConcreteObserver : public IObserver {
public:void update(const std::string& message) override {std::cout << "Observer received message: " << message << std::endl;// 在此处响应状态变更,执行观察者的相关操作}
};// 使用示例
int main() {ConcreteSubject subject;ConcreteObserver observer1;ConcreteObserver observer2;subject.registerObserver(&observer1);subject.registerObserver(&observer2);subject.changeState("New State"); // 当状态变化时,所有观察者都会被通知return 0;
}

在这个例子中,ConcreteSubject 是具体的主题类,它可以添加和移除观察者,并在状态变化时通过调用 notifyObservers() 方法通知所有的观察者。ConcreteObserver 类则是实现了 IObserver 接口的观察者,当收到 update() 调用时,会执行相应的更新操作。主程序中创建了一个主题实例和两个观察者实例,并将观察者注册到主题上,当主题状态发生变化时,观察者接收到通知并作出反应。

在实际应用中,观察者模式通常用于设计事件驱动的系统,或者是当对象的状态变化需要自动通知其他对象时。以下是对上述代码实例的进一步阐述:

  1. 应用场景举例:假设你正在构建一个气象站系统,其中ConcreteSubject代表气象站,它记录并报告实时天气数据。ConcreteObserver可以代表各种订阅气象信息的实体,如天气预报网站、农业自动化系统、交通管理系统等。

  2. 主体(Subject):当气象站检测到天气数据发生改变时,例如温度、湿度或风速变化,它会调用notifyObservers()方法,通知所有已注册的观察者。

  3. 观察者(Observer):每一个观察者在接收到update()调用时,会按照自己的需求处理这个更新消息。比如,天气预报网站会在页面上实时更新数据,农业自动化系统会据此调整灌溉计划,交通管理系统则可能据此发布道路预警信息。

  4. 灵活性:观察者模式提供了很好的灵活性,因为新增加的观察者只需实现IObserver接口,并通过主题的registerObserver()方法注册自己,就可以开始接收更新通知,而不需要修改原有的主体或其它观察者。

  5. 松耦合:通过观察者模式,主题与观察者之间的耦合度较低,两者之间通过接口进行交互,这有助于简化系统的维护和扩展。

总之,通过这个简单的C++观察者模式实例,我们可以了解到如何构建一个具有动态通知机制的系统,使得当对象状态改变时,它的所有依赖对象都能得到及时的更新。在实际开发中,观察者模式广泛应用于GUI编程、事件处理、游戏开发、分布式系统等多种场景。

C++观察者模式代码实例二

另外,观察者模式还可以结合C++的一些现代特性进行优化,例如使用智能指针来管理观察者生命周期,以避免内存泄漏问题。下面是一个使用std::shared_ptr改进后的观察者列表管理的例子:

#include <iostream>
#include <vector>
#include <memory>// 观察者接口(Observer)
class IObserver {
public:virtual ~IObserver() {}virtual void update(const std::string& message) = 0;
};// 主题接口(Subject)
class ISubject {
public:virtual ~ISubject() {}virtual void attach(std::shared_ptr<IObserver> observer) = 0;virtual void detach(std::shared_ptr<IObserver> observer) = 0;virtual void notifyObservers(const std::string& message) = 0;
};// 具体主题(ConcreteSubject)
class ConcreteSubject : public ISubject {
private:std::vector<std::shared_ptr<IObserver>> observers;public:void attach(std::shared_ptr<IObserver> observer) override {observers.push_back(observer);}void detach(std::shared_ptr<IObserver> observer) override {observers.erase(std::remove(observers.begin(), observers.end(), observer),observers.end());}void notifyObservers(const std::string& message) override {for (const auto& obs : observers) {obs->update(message);}}// 其他业务逻辑...
};// 具体观察者(ConcreteObserver)
class ConcreteObserver : public IObserver {
public:void update(const std::string& message) override {std::cout << "Observer received message: " << message << std::endl;// 在此处响应状态变更,执行观察者的相关操作}
};// 使用示例
int main() {ConcreteSubject subject;auto observer1 = std::make_shared<ConcreteObserver>();auto observer2 = std::make_shared<ConcreteObserver>();subject.attach(observer1);subject.attach(observer2);subject.notifyObservers("New State"); // 当状态变化时,所有观察者都会被通知return 0;
}

在这个改进版中,观察者列表现在存储的是指向观察者的智能指针,这样当观察者不再需要时,可以自动释放其占用的内存,有效防止了内存泄漏。同时,这也使得主题类与观察者之间的关系管理更加安全和可靠。

此外,观察者模式还可以与C++11/14/17的新特性结合起来,以更好地适应现代C++编程实践。例如:

  1. Lambda 表达式:在某些情况下,你可以使用lambda表达式作为临时观察者,这样就不必为一次性任务专门创建一个类。例如:
subject.attach([&](const std::string& message) {std::cout << "Anonymous observer received message: " << message << std::endl;
});subject.notifyObservers("New State");
  1. std::functionstd::bind:如果你需要传递已经存在的函数或成员函数作为观察者,可以使用std::functionstd::bind来包装这些函数。例如,假设你有一个打印日志的全局函数或类成员函数:
void logMessage(const std::string& message) {std::cout << "Log system received message: " << message << std::endl;
}// 全局函数
subject.attach(logMessage);// 成员函数,假设有一个Logger类
class Logger {
public:void log(const std::string& message) {std::cout << "Logger received message: " << message << std::endl;}
};Logger logger;
subject.attach(std::bind(&Logger::log, &logger, std::placeholders::_1));

通过这些现代C++特性的应用,观察者模式变得更加灵活,可以适应更多样化的场景和需求。同时,结合智能指针和其他内存管理工具,观察者模式的实现可以变得更安全、更易于维护。

除此之外,观察者模式还可以与C++17中的std::variantstd::visit配合使用,以处理不同类型的通知消息。例如,当主题拥有多种状态需要向观察者发送时,可以定义一个包含所有可能状态类型的std::variant变量:

#include <variant>enum class WeatherDataType { Temperature, Humidity, WindSpeed };struct WeatherData {WeatherDataType type;double value;
};class ConcreteSubject : public ISubject {// ...void notifyObservers(WeatherData data) override {for (const auto& obs : observers) {obs->update(data);}}
};class AdvancedObserver : public IObserver {
public:void update(const WeatherData& data) override {std::visit(overloaded{[&](const auto& value) {if (data.type == WeatherDataType::Temperature)handleTemperature(value);// 处理其他类型...},}, data.value);}private:void handleTemperature(double temp) {std::cout << "Received temperature update: " << temp << std::endl;}// 处理其他数据类型的方法...
};

在此案例中,WeatherData结构体包含了数据类型和对应的值,观察者可以根据type字段判断所接收数据的具体类型,并通过std::visit调用相应的方法进行处理。

综上所述,观察者模式与现代C++特性相结合,可以构建出更加灵活、类型安全且易于维护的系统,适用于各种复杂的事件驱动和状态变更通知场景。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/708266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Unity实战】UGUI和Z轴排序那点事儿

如果读者是从Unity 4.x时代过来的&#xff0c;可能都用过NGUI这个插件&#xff08;后来也是土匪成了正规军&#xff09;&#xff0c;NGUI一大特点是可以靠transform位移的Z值进行遮挡排序&#xff0c;然而这个事情在UGUI成了难题&#xff08;Sorting Layer、Inspector顺序等因素…

品牌百度百科应该怎样创建?编辑品牌百度百科词条的秘籍!

在数字化时代&#xff0c;品牌的故事不仅仅存在于广告牌和电视屏幕上&#xff0c;它们还在互联网的每一个角落悄然讲述。百度百科词条作为中国最大的中文百科全书&#xff0c;成为了品牌展示自身故事的重要舞台。那么&#xff0c;如何在这个舞台上留下你的品牌印记呢&#xff1…

solidity编程

一.Solidity 简介 Solidity 是⼀种⽤于编写以太坊虚拟机&#xff08; EVM &#xff09;智能合约的 编程语⾔。我认为掌握 Solidity 是参与链上项⽬的必备技 能&#xff1a;区块链项⽬⼤部分是开源的&#xff0c;如果你能读懂代码&#xff0c;就可以 规避很多亏钱项⽬。…

RK3568 android11 调试陀螺仪模块 MPU-6500

一&#xff0c;MPU6500功能介绍 1.简介 MPU6500是一款由TDK生产的运动/惯性传感器&#xff0c;属于惯性测量设备&#xff08;IMU&#xff09;的一种。MPU6500集成了3轴加速度计、3轴陀螺仪和一个板载数字运动处理器&#xff08;DMP&#xff09;&#xff0c;能够提供6轴的运动…

Outlook邮箱IMAP怎么开启?服务器怎么填?

Outlook邮箱IMAP服务器如何开启&#xff1f;Outlook设置IMAP的方法&#xff1f; Outlook邮箱作为其中的佼佼者&#xff0c;被广大用户所青睐。但在使用Outlook邮箱时&#xff0c;许多用户可能会碰到一个问题&#xff1a;如何开启IMAP服务&#xff1f;下面&#xff0c;蜂邮EDM就…

解决鸿蒙模拟器卡顿的问题

缘起 最近在学习鸿蒙的时候&#xff0c;发现模拟器非常卡&#xff0c;不要说体验到鸿蒙的丝滑&#xff0c;甚至到严重影响使用的程度。 根据我开发Android的经验和在论坛翻了一圈&#xff0c;最终总结出了以下几个方案。 创建模拟器 1、在DevEco Virtual Device Configurat…

【InternLM 实战营笔记】LMDeploy 的量化和部署

环境配置 vgpu-smi 查看显卡资源使用情况 新开一个终端执行下面的命令实时观察 GPU 资源的使用情况。 watch vgpu-smi复制环境到我们自己的 conda 环境 /root/share/install_conda_env_internlm_base.sh lmdeploy激活环境 conda activate lmdeploy安装依赖库 # 解决 Modu…

day04_拦截器Apifox角色管理(登录校验,API接口文档,权限管理说明,角色管理,添加角色,修改角色,删除角色)

文章目录 1. 登录校验1.1 需求说明1.2 实现思路1.3 ThreadLocal1.4 AuthContextUtil1.5 拦截器使用1.5.1 拦截器开发1.5.2 拦截器注册 1.6 代码优化1.6.1 配置优化1.6.2 代码优化1.6.3 前端修改 2. API接口文档2.1 Apifox接口管理平台2.1.1 接口管理平台简介2.1.2 Apifox简介2.…

【kubernetes】关于云原生之k8s集群的pod理论详解

目录 一、pod的基础概念 什么是pod&#xff1f; k8s集群中pod的两种使用方式 pod中运行容器的原则&#xff1a; 创建pod的3种方式 第一种&#xff1a;自主式Pod 第二种&#xff1a;控制器管理的Pod 第三种&#xff1a;静态Pod 二、pod中容器的基础概念 pod容器的分类 …

记录工作中遇见问题、学习项

1、判空操作 Demo demo Optional .ofNullable(demoService.getById(id)) .orElseThrow(() -> new ServiceException("不存在id为" id "的数据")); 2、SQL方面 1、group by : GROUP BY 子句必须放在 WHERE 子句中的条件之后&#…

Apache SeaTunnel 及 Web 功能部署指南(小白版)

在大数据处理领域&#xff0c;Apache SeaTunnel 已成为一款备受青睐的开源数据集成平台&#xff0c;它不仅可以基于Apache Spark和Flink&#xff0c;而且还有社区单独开发专属数据集成的Zeta引擎&#xff0c;提供了强大的数据处理能力。随着SeaTunnel Web的推出&#xff0c;用户…

雾锁王国服务器要开服务器吗?

雾锁王国要开服务器吗&#xff1f;可以使用官方服务器&#xff0c;也可以自己搭建多人联机服务器&#xff0c;更稳定不卡&#xff0c;畅玩开黑。阿腾云分享atengyun.com给大家目前阿里云和腾讯云均提供雾锁王国服务器和一键搭建程序&#xff0c;成本26元即可搭建一台自己的雾锁…

Keepalived双机热备——Haproxy搭建web群集

一、认识keepalived keepalived是一个开源的软件&#xff0c;用于实现高可用性和负载均衡。它主要用于在多个服务器之间提供故障转移和负载均衡的功能。keepalived可以监控服务器的状态&#xff0c;并在主服务器发生故障时自动将备份服务器切换为主服务器&#xff0c;以确保服…

高压高能碳陶瓷无感电阻的制作以及应用?

由于现有需求&#xff0c;许多现代电子电路和设备都会经历瞬态脉冲和浪涌。这反过来又导致需要“设计”瞬态浪涌保护&#xff0c;尤其是在电机控制器等电路中。当电机启动时&#xff0c;此时消耗的电流过大&#xff0c;可能导致电阻器故障。同样&#xff0c;如果电容器用于电机…

揭示IP风险画像的作用与价值

在当今数字化时代&#xff0c;互联网的快速发展为企业和个人带来了巨大的机遇&#xff0c;同时也带来了各种安全风险和威胁。随着网络攻击手段的不断升级和演变&#xff0c;传统的安全防御手段已经无法满足对抗复杂多变的网络威胁的需求。IP风险画像作为一种新型的网络安全解决…

2024.2.28 网络

思维导图 整理面试题 1、什么是回调函数 答&#xff1a;将函数作为参数传到另一个函数里面&#xff0c;当那个函数执行完之后&#xff0c;再执行传进去的这个函数。这个过程就叫做回调。 2、结构体和共用体的区别 答&#xff1a;结构体的每个成员都会分配内存&#xff0c;…

加密与安全_深入了解哈希算法

文章目录 Pre概述哈希碰撞常用的哈希算法Codejava.security.MessageDigestMD5SHA-1SHA-256MessageDigest支持算法 哈希算法的用途彩虹表攻击基本原理攻击过程 防御彩虹表攻击基本原理用途 小结 Pre PKI - 01 散列(Hash)函数 概述 哈希算法&#xff08;Hash&#xff09;又称摘…

c# 异常处理

异常类 .NET Framework 类库中的所有异常都派生于 Exception 类&#xff0c;异常包括系统异常和应用异常。 默认所有系统异常派生于 System.SystemException&#xff0c;所有的应用程序异常派生于 System.ApplicationException。 系统异常一般不可预测&#xff0c;比如内存堆…

python中版本,操作系统等问题汇总

1. linux源码部署到windows 1.1ModuleNotFoundError: No module named pwd 这个问题&#xff0c;是因为源码是给linux的。这里在windows中&#xff0c;没有该命令。 解决方法之一&#xff0c;在相应的环境目录中&#xff0c;如图中<MetaGPTenv>虚拟环境中&#xff0c;在…

nginx(三)实现反向代理客户端 IP透传

正常情况下&#xff0c;客户端去访问代理服务器&#xff0c;然后代理服务器再取访问真实服务器&#xff0c;在真实服务器上&#xff0c;只能显示代理服务器的ip地址&#xff0c;而不显示客户端的ip地址&#xff0c;如果想让客户端的ip地址也能在真实服务端看见&#xff0c;这一…