c++如何实现观察者模式_C++发布订阅机制的设计实例


观察者模式通过定义一对多依赖关系,实现对象间松耦合通信。1. 使用抽象接口:定义Observer基类和Subject类,通过继承与虚函数实现通知机制,适合需要多态的场景。2. 使用std::function:以函数对象替代继承,支持lambda、函数指针等可调用对象,提升灵活性。3. 智能指针版本:结合shared_ptr与weak_ptr自动管理订阅生命周期,避免悬空指针。适用于GUI事件、MVC架构、消息总线等场景,建议根据需求选择继承或回调方式,并注意线程安全与资源管理。

观察者模式(Observer Pattern),也叫发布-订阅模式,是一种行为设计模式,用于在对象之间定义一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会自动收到通知。在 C++ 中实现这一机制,可以通过抽象基类、函数指针、std::function 或智能指针等现代 C++ 特性来完成。

1. 使用抽象接口实现观察者模式

这是最经典的方式,通过定义观察者和被观察者的抽象接口,实现松耦合通信。

步骤说明:

  • 定义一个 Observer 抽象类,包含纯虚函数 update()。
  • 定义一个 Subject 类,维护观察者列表,提供注册、移除和通知接口。
  • 具体观察者继承 Observer,实现自己的 update 行为。

代码示例:

#include 
#include 
#include 

class Observer;

class Subject { private: std::vector observers; int state;

public: void attach(Observer obs); void detach(Observer obs); void notify(); void setState(int s); int getState() const { return state; } };

class Observer { protected: Subject subject; public: explicit Observer(Subject s) : subject(s) { subject->attach(this); } virtual ~Observer() { subject->detach(this); } virtual void update() = 0; };

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

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

void Subject::notify() { for (auto obs : observers) { obs->update(); } }

void Subject::setState(int s) { state = s; notify(); }

// 具体观察者 class ConcreteObserverA : public Observer { public: explicit ConcreteObserverA(Subject* s) : Observer(s) {} void update() override { std::cout << "Observer A: Subject state is now " << subject->getState() << "\n"; } };

class ConcreteObserverB : public Observer { public: explicit ConcreteObserverB(Subject* s) : Observer(s) {} void update() override { std::cout << "Observer B: Subject state changed to " << subject->getState() << "\n"; } };

使用方式:

int main() {
    Subject subject;
    ConcreteObserverA observerA(&subject);
    ConcreteObserverB observerB(&subject);
subject.setState(10);  // 两个观察者都会收到通知
subject.setState(20);

return 0;

}

2. 使用 std::function 实现更灵活的订阅机制

如果不想使用继承,可以用函数对象代替抽象类,让订阅者更加灵活,支持 lambda、函数指针或任意可调用对象。

#include 
#include 
#include 
#include 

class EventSystem { private: std::vector> listeners;

public: // 订阅事件 void subscribe(std::function callback) { listeners.push_back(callback); }

// 发布事件
void publish(int value) {
    for (const auto& listener : listeners) {
        listener(value);
    }
}

};

使用示例:

int main() {
    EventSystem eventBus;
// 使用 lambda 订阅
eventBus.subscribe([](int val) {
    std::cout zuojiankuohaophpcnzuojiankuohaophpcn "Logger: Value updated to " zuojiankuohaophpcnzuojiankuohaophpcn val zuojiankuohaophpcnzuojiankuohaophpcn "\n";
});

eventBus.subscribe([](int val) {
    if (val youjiankuohaophpcn 50) {
        std::cout zuojiankuohaophpcnzuojiankuohaophpcn "Alert: High value detected: " zuojiankuohaophpcnzuojiankuohaophpcn val zuojiankuohaophpcnzuojiankuohaophpcn "\n";
    }
});

// 模拟数据变化
eventBus.publish(30);
eventBus.publish(60);

return 0;

}

3. 支持自动解绑的智能指针版本(进阶)

为了避免手动管理生命周期导致的悬空指针问题,可以结合 std::shared_ptrweak_ptr 实现自动清理。

思路:每个订阅者返回一个句柄(token),当句柄销毁时自动从列表中移除。或者使用 weak_ptr 存储回调,在调用前检查是否有效。

#include 
#include 
#include 
#include 

class Publisher { private: struct CallbackWrapper { std::weak_ptr> cb; }; std::vector callbacks;

public: std::shared_ptr> subscribe(std::function func) { auto shared_func = std::make_shared>(func); callbacks.push_back({shared_func}); return shared_func; // 返回共享指针作为“订阅句柄” }

void publish(int value) {
    callbacks.erase(
        std::remove_if(callbacks.begin(), callbacks.end(),
            [value](const CallbackWrapper& wrapper) {
                auto locked = wrapper.cb.lock();
                if (locked) {
                    (*locked)(value);
                    return false;
                }
                return true;  // 已失效,移除
            }),
        callbacks.end()
    );
}

};

这样当外部持有的 shared_ptr 被释放,下次 publish 时会自动清理无效项。

应用场景与建议

观察者模式适用于以下场景:

  • GUI 事件系统(按钮点击通知多个组件)
  • 模型-视图架构中,模型更新通知视图刷新
  • 日志系统、消息总线、状态监控等

设计建议:

- 若需要多态行为,使用接口 + 继承方式。 - 若注重灵活性和轻量级,推荐 std::function + 回调。 - 注意循环引用和生命周期管理,尤其是在使用智能指针时。 - 线程安全需额外加锁(如 std::mutex),若跨线程发布。

基本上就这些。根据项目复杂度选择合适实现方式即可。


# go  # app  # ai  # c++  # ios  # stream  # red  # mvc  # 架构  # 多态  # Token  # 循环  # Lambda  # 指针  # 继承  # 虚函数  # 纯虚函数  # 接口  # 线程  # 空指针  # function  # 对象  # 事件  # 句柄  # 回调  # 移除  # 适用于  # 自己的  # 进阶  # 这是  # 这一  # 是在  # 是一种 


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


相关推荐: Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  Win11如何关闭小娜Cortana Win11禁用Cortana语音助手【优化】  c++怎么使用std::filesystem遍历文件夹_c++ 递归查找文件与权限修改【技巧】  Windows系统被恶意软件破坏后的恢复策略_错误提示修复方式  Win11怎么关闭专注助手 Win11关闭免打扰模式设置【操作】  Windows音频驱动无声音原因解析_声卡驱动错误修复步骤  VSC怎么快速定位PHP错误行_错误追踪设置法【方法】  php删除数据怎么加限制_带where条件删除避免全删【指南】  Python如何创建带属性的XML节点  Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  mac怎么打开终端_MAC终端Terminal使用入门与常用命令【教程】  c++协程和线程的区别 c++异步编程模型对比【核心】  Win11怎么检查TPM2.0模块_Windows11受信任平台模块开启状态查询  Windows10怎么用“讲述人”读屏辅助 Windows10轻松使用开启讲述人朗读屏幕文字帮助视障用户【教程】  如何在 PHP 中按相同键合并两个关联数组为二维数组  Python数据抓取合法性_合规说明【指导】  Windows10系统怎么查看IP地址_Win10网络连接状态详细信息  Win11怎么设置任务栏大小_Windows11注册表修改TaskbarSi值  Windows10系统怎么查看设备管理器_Win10快捷键Win+X菜单使用  Mac如何与安卓手机传文件_Mac和Android设备互通【必备工具】  C#如何在一个XML文件中查找并替换文本内容  Win10系统更新错误0x80240034怎么办 Win10更新错误解决法【方法】  Mac如何调整Dock栏大小和位置_Mac程序坞个性化设置  Win11怎么设置虚拟内存_Windows 11优化内存性能提升速度【技巧】  Win11麦克风没声音怎么设置_Win11麦克风权限及驱动修复【教程】  Win11怎么更改任务栏位置_修改注册表将Win11任务栏置顶【教程】  如何在Golang中实现并发消息队列消费者_Golang channel消息消费实践  Python日志系统设计与实现_高可观测性架构实战  Win11怎么开启移动热点_Windows11共享网络给手机设置教程  如何使用 Selenium 正确获取篮球参考网站球员名单元素列表  LINUX怎么查看进程_LINUX ps命令查看运行服务  如何使用正则表达式提取以编号开头、后跟多个注解的完整代码块  c++怎么使用std::unique实现去重_c++ 容器元素排序与连续重复删除【教程】  Win11怎么设置任务栏透明_Windows11使用工具美化任务栏  windows 10应用商店区域怎么改_windows 10微软商店切换地区方法  Win11如何连接Xbox手柄 Win11蓝牙连接游戏手柄教程【步骤】  如何使用Golang配置安全开发环境_防止敏感信息泄露  Win11怎么设置触控板手势_Windows11三指四指操作自定义  Win10怎样清理C盘阿里旺旺缓存_Win10清理阿里旺旺缓存步骤【步骤】  Win11怎么关闭OneDrive同步_Win11取消自动备份文件【教程】  Win11怎么设置ip地址_Windows 11手动配置网络IP教程【详解】  c++中如何使用虚函数实现多态_c++多态性实现原理  Win11怎么打开注册表_Windows 11注册表编辑器启动命令【步骤】  如何在Golang中实现WebSocket广播_使用Channel和协程分发消息  Win11怎么关闭SmartScreen_禁用Windows Defender筛选器教程【步骤】  Win11怎么关闭开机声音_Win11系统启动提示音静音【教程】  Win11怎么关闭透明效果_Windows11个性化颜色关闭透明  Win11怎么设置默认输入法 Win11固定中文输入法【步骤】  Go 中实现 Python urllib.quote() 功能的等效方法  如何在 Go 中高效缓存与分发网络视频流 

 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.