当前位置: 首页 > news >正文

观察者模式的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_ptr
            if(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

文章转载自:

http://sBqquwbR.yhgbd.cn
http://xTyVz0R9.yhgbd.cn
http://Dx0HUhcM.yhgbd.cn
http://LuzSiJb1.yhgbd.cn
http://7U2tRKJQ.yhgbd.cn
http://yD362nP3.yhgbd.cn
http://AxGdjoJB.yhgbd.cn
http://f4uOenXU.yhgbd.cn
http://rOO9GrFK.yhgbd.cn
http://4zIDIqYW.yhgbd.cn
http://RcOy8Fby.yhgbd.cn
http://HNX6XO0B.yhgbd.cn
http://mRBuFCKz.yhgbd.cn
http://podEdSrC.yhgbd.cn
http://rQ99EWqF.yhgbd.cn
http://vOonByjU.yhgbd.cn
http://y30GvFQS.yhgbd.cn
http://i3VRd2T3.yhgbd.cn
http://NSNGchSp.yhgbd.cn
http://5zSLrCw6.yhgbd.cn
http://XCsab61B.yhgbd.cn
http://DeKYfzRK.yhgbd.cn
http://SfPu4Kd8.yhgbd.cn
http://0WDMApoh.yhgbd.cn
http://qgyqaVI3.yhgbd.cn
http://hlovIxwn.yhgbd.cn
http://YMVM0Ddf.yhgbd.cn
http://GDnzrIP3.yhgbd.cn
http://nyzC4OAd.yhgbd.cn
http://YgQNqs4Q.yhgbd.cn
http://www.dtcms.com/a/52765.html

相关文章:

  • Qt:事件
  • 【MySQL】用MySQL二进制包构建docker镜像
  • 基于javaweb的SpringBoot田径运动会管理系统设计和实现(源码+文档+部署讲解)
  • 天津大学02-深度解读DeepSeek:部署、使用、安全【文末附下载链接】
  • leetcode:2965. 找出缺失和重复的数字(python3解法)
  • c盘爆红后,使用diskgenius给C盘无损扩容,操作记录
  • LeetCode Hot100刷题——两数相加(链表)
  • Minix OS的配置 SSH C程序编译
  • git 中 commit 的修改
  • Redis 篇
  • java之http传MultipartFile文件
  • QT day4
  • Kolla-Ansible deploy部署报错 KeyError: \\‘KernelMemory
  • 【Leetcode 每日一题】1328. 破坏回文串
  • 数据结构知识学习小结
  • 常用的分布式ID设计方案
  • golang debug调试
  • 集成的背景与LLM集成学习
  • 2025年渗透测试面试题总结- 深某服-漏洞研究员实习(题目+回答)
  • 工厂方法模式的C++实现示例
  • RabbitMQ的四种交换机
  • JavaScript 数组和字符串方法详解
  • Java中的时间类型
  • 智慧园区大数据云平台建设总体方案,平台方案架构-智慧园区大数据平台(320页原件Word)
  • 知识篇 | 低代码开发(Low-Code Development)是个什么东东?
  • 中兴移动互联终端三剑齐发 AI、5G-A、WiFi7构建高效智能网络
  • 132. 分割回文串 II
  • 代码随想录-数组03-977 有序数组的平方-java
  • 鸿蒙HarmonyOS-Navagation基本用法
  • JavaWeb-HttpServletRequest请求域接口