c++怎么实现一个观察者模式_c++事件通知与解耦机制实现


观察者模式通过Subject与Observer接口实现一对多依赖更新。1. Subject维护观察者列表,状态变化时通知所有Observer;2. Observer定义update纯虚函数接收通知;3. 使用智能指针与弱引用避免内存泄漏和悬挂指针;4. 加入互斥锁保障多线程安全;5. 适用于事件系统、日志广播等解耦场景。

观察者模式是一种行为设计模式,用于在对象之间建立一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知并自动更新。在C++中,这种机制常被用来实现事件通知系统,达到模块间的解耦。

核心思路与角色划分

观察者模式包含两个主要角色:

  • Subject(被观察者):维护观察者列表,提供注册、注销和通知接口。
  • Observer(观察者):定义接收通知的接口,通常是一个纯虚函数。

通过抽象接口,Subject不需要知道具体是谁在监听,实现了发送方与接收方的解耦。

基础实现示例

下面是一个简洁的C++实现:

#include 
#include 
#include 

// 观察者接口 class Observer { public: virtual ~Observer() = default; virtual void update(const std::string& message) = 0; };

// 被观察者 class Subject { private: std::vector observers;

public: void attach(Observer* obs) { observers.push_back(obs); }

void detach(Observer* obs) {
    observers.erase(
        std::remove(observers.begin(), observers.end(), obs),
        observers.end()
    );
}

void notify(const std::string& message) {
    for (auto* obs : observers) {
        obs-youjiankuohaophpcnupdate(message);
    }
}

};

定义两个具体的观察者:

class ConcreteObserverA : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "Observer A received: " << message << "\n";
    }
};

class ConcreteObserverB : public Observer { public: void update(const std::string& message) override { std::cout << "Observer B received: " << message << "\n"; } };

使用方式:

int main() {
    Subject subject;
    ConcreteObserverA observerA;
    ConcreteObserverB observerB;
subject.attach(&observerA);
subject.attach(&observerB);

subject.notify("Hello Observers!");

subject.detach(&observerA);
subject.notify("Only B should see this.");

return 0;

}

改进:支持多线程与智能指针

上面的实现存在裸指针管理问题。实际项目中建议使用std::weak_ptr避免悬挂指针,并考虑线程安全。

改用std::shared_ptrstd::weak_ptr

#include 
#include 

class Observer;

class Subject { private: std::list> observers; mutable std::mutex mtx; // 线程安全

public: void attach(std::shared_ptr obs) { std::lock_guard lock(mtx); observers.remove_if([](const auto& w) { return w.expired(); }); observers.push_back(obs); }

void notify(const std::string& message) {
    std::lock_guardzuojiankuohaophpcnstd::mutexyoujiankuohaophpcn lock(mtx);
    observers.remove_if([&](const auto& w) {
        if (auto obs = w.lock()) {
            obs-youjiankuohaophpcnupdate(message);
            return false;
        }
        return true; // 已过期,移除
    });
}

};

观察者也改为继承 enable_shared_from_this:

class Observer : public std::enable_shared_from_this {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& message) = 0;
};

应用场景与优势

观察者模式适合以下场景:

  • GUI事件系统(按钮点击、窗口关闭)
  • 消息广播机制
  • 日志系统多输出目标
  • 游戏中的事件驱动逻辑

优点包括:

  • 松耦合:Subject不依赖具体Observer
  • 可扩展:新增观察者无需修改现有代码
  • 动态订阅:运行时灵活添加或移除监听者

基本上就这些。关键是理解“发布-订阅”思想,用接口隔离变化,再结合现代C++特性提升安全性和可用性。实际项目中也可考虑使用信号槽库(如Boost.Signals2)来简化实现。


# go  # ai  # c++  # ios  # stream  # red  # 指针  # 继承  # 虚函数  # 纯虚函数  # 接口  # 线程  # 多线程  # 对象  # 事件  # 是一个  # 移除  # 是一种  # 适用于  # 也可  # 可用性  # 要知道  # 不需  # 谁在 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化76771 】 【 技术知识130152 】 【 IDC云计算60162 】 【 营销推广131313 】 【 AI优化88182 】 【 百度推广37138 】 【 网站推荐60173 】 【 精选阅读31334


相关推荐: Win11怎么格式化U盘_Win11系统U盘格式化与文件系统选择【教程】  Win11怎么设置闹钟_Windows 11时钟应用闹钟设置指南【详解】  Win10怎么卸载鲁大师_Win10彻底卸载鲁大师方法【步骤】  Win11怎么关闭通知中心_Windows11系统通知与专注助手设置  Win11怎么设置任务栏图标大小_Windows11注册表TaskbarSi修改  C++如何解析JSON数据?(nlohmann/json库示例)  如何在 ACF 中正确更新嵌套多层 Group 字段内的子字段  如何在 Django 中安全修改用户密码而不使会话失效  如何在Golang中配置代码格式化工具_使用gofmt和goimports  Win11文件夹预览图不显示怎么办_Win11缩略图缓存重建修复【教程】  Windows系统文件被保护机制阻止怎么办_权限不足错误处理方案  Win11如何设置系统声音_Win11系统声音调整教程【攻略】  Mac如何解压zip和rar文件?(推荐免费工具)  Golang如何避免指针逃逸_Golang逃逸分析与堆栈优化策略  Win11输入法切换快捷键怎么改_Windows 11自定义语言切换键位【教程】  php订单日志怎么在swoole写_php协程swoole写订单日志教程【教程】  Go语言中slice追加操作的底层共享机制详解  微信短链接怎么还原php_用浏览器开发者工具抓包获取【方法】  Linux怎么查找死循环进程_Linux系统负载分析与进程彻底结束【教程】  php条件判断怎么写_ifelse和switchcase的使用区别【对比】  php485函数执行慢怎么优化_php485性能提升小技巧【技巧】  如何使用Golang benchmark测量函数延迟_统计执行耗时  Win11怎么激活Windows10_Win11激活Win10系统方法【步骤】  Win11 C盘满了怎么清理 Win11磁盘清理和存储感知使用教程【新手必看】  Win11如何设置鼠标灵敏度_Win11鼠标灵敏度调整教程【攻略】  Windows10如何查看保存的WiFi密码_Win10命令行netsh wlan查询  php下载安装后memory_limit怎么设置_内存限制调整【技巧】  如何在 Go 应用中实现自动错误恢复与进程重启机制  如何使用Golang实现容器健康检查_监控和自动重启  如何理解Go指针和内存分配关系_Go Pointer内存Model解析  MySQL 中使用 IF 和 CASE 实现查询字段条件化显示  Win11时间格式怎么改成12小时制 Win11时间格式切换教程【步骤】  php怎么下载安装后测试是否成功_简单脚本验证方法【操作】  使用类变量定义字符串常量时如何实现类型安全的 Literal 注解  php命令行怎么运行_通过CLI模式执行PHP脚本的步骤【说明】  Win10怎么卸载金山毒霸_Win10彻底卸载金山毒霸方法【步骤】  Linux怎么禁止Root用户远程登录_Linux系统SSH加固与安全设置【教程】  Win10怎样卸载DockerDesktop_Win10卸载DockerDesktop步骤【步骤】  C++如何编写函数模板?(泛型编程入门)  Win11文件扩展名怎么显示_Win11查看文件后缀名设置【基础】  MySQL 中使用 IF 和 CASE 实现查询字段的条件转换  LINUX怎么查看进程_LINUX ps命令查看运行服务  Windows蓝屏BAD_POOL_HEADER故障详解_蓝屏池损坏错误修复指南  php485能和物联网模块通信吗_php485对接NB-IoT模块实例【说明】  Python数据挖掘进阶教程_分类回归与聚类案例解析  如何在Golang中实现基础配置管理功能_Golang配置文件读取与更新示例  Win10如何关闭安全中心所有通知 Win10禁用Windows Defender提醒【设置】  如何使用Golang实现基本类型比较_Golang比较操作符使用方法  Win11怎么关闭系统声音_Win11系统提示音静音设置【详解】  Win11怎么设置任务栏对齐方式_Windows11个性化任务栏行为 

 2025-11-19

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.