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

C++中的观察者模式:通俗易懂的讲解与实现

什么是观察者模式?

观察者模式是一种常见的设计模式,它解决了这样一个问题:当某个对象的状态发生变化时,如何通知依赖它的其他对象?

用通俗的话说,观察者模式就像我们日常的“订阅-通知”机制:

  • 主题(Subject) 是信息的提供者(比如新闻网站、天气站)。
  • 观察者(Observer) 是信息的订阅者(比如读者、天气App)。
  • 当主题有了新的变化(如新闻更新、天气变化),会通知所有订阅的观察者。

观察者模式的特点

  1. 松耦合
    主题和观察者之间通过接口交互,彼此不直接依赖,可以独立扩展。

  2. 动态订阅与取消订阅
    观察者可以随时订阅或取消订阅,运行时非常灵活。

  3. 通知机制自动化
    主题变化后,会统一通知所有订阅者。


适用场景

  1. 消息通知
    比如新闻推送系统,用户订阅后,新闻更新会自动推送。

  2. 数据驱动更新
    在界面设计中,数据变化时需要动态更新UI(如MVC架构)。

  3. 事件触发系统
    游戏中玩家状态变化需要通知其他玩家,或者股票系统推送实时行情。


C++实现观察者模式:天气预报案例

为了演示观察者模式,我们用一个天气预报系统来举例:

  • 主题(WeatherStation): 模拟一个天气站,用于监控和更新天气。
  • 观察者(WeatherApp): 模拟订阅天气的手机App,接收天气通知。

完整代码

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <string>

// 抽象观察者接口
class WeatherObserver {
public:
    virtual void updateWeather(const std::string& weather) = 0; // 收到天气更新通知的方法
    virtual ~WeatherObserver() = default;
};

// 抽象主题类(天气站)
class WeatherStation {
private:
    std::vector<std::shared_ptr<WeatherObserver>> observers; // 保存订阅者列表
    std::string currentWeather; // 当前天气

public:
    // 添加观察者(订阅)
    void addObserver(std::shared_ptr<WeatherObserver> observer) {
        observers.push_back(observer);
    }

    // 移除观察者(取消订阅)
    void removeObserver(std::shared_ptr<WeatherObserver> observer) {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    // 通知所有观察者
    void notifyObservers() {
        for (const auto& observer : observers) {
            observer->updateWeather(currentWeather);
        }
    }

    // 更新天气并通知观察者
    void updateWeather(const std::string& weather) {
        currentWeather = weather;
        notifyObservers(); // 通知所有观察者天气变化
    }
};

// 具体观察者类(手机App)
class WeatherApp : public WeatherObserver {
private:
    std::string appName; // App的名字

public:
    explicit WeatherApp(const std::string& name) : appName(name) {}

    // 实现天气更新通知方法
    void updateWeather(const std::string& weather) override {
        std::cout << appName << " 收到了最新天气:" << weather << std::endl;
    }
};

// 主函数:测试观察者模式
int main() {
    // 创建天气站(主题)
    std::shared_ptr<WeatherStation> station = std::make_shared<WeatherStation>();

    // 创建两个观察者(手机App)
    std::shared_ptr<WeatherObserver> app1 = std::make_shared<WeatherApp>("天气宝App");
    std::shared_ptr<WeatherObserver> app2 = std::make_shared<WeatherApp>("气象通App");

    // 两个App订阅天气站
    station->addObserver(app1);
    station->addObserver(app2);

    // 更新天气,触发通知
    station->updateWeather("晴天");
    station->updateWeather("下雨");

    // 取消天气宝App的订阅
    station->removeObserver(app1);

    // 再次更新天气,验证通知
    station->updateWeather("大风");

    return 0;
}

代码拆解与分析

  1. 抽象观察者接口(WeatherObserver

    • 定义了一个虚函数 updateWeather(),所有观察者类都必须实现这个方法,用来接收通知。
  2. 主题类(WeatherStation

    • 保存了一个观察者列表(std::vector),用于管理所有订阅者。
    • 提供了 addObserver()removeObserver() 方法,方便动态添加或移除观察者。
    • 通过 notifyObservers() 方法通知所有观察者。
  3. 具体观察者(WeatherApp

    • 每个观察者都实现了 updateWeather() 方法,用来处理天气变化的通知。
  4. 运行逻辑

    • 创建主题和观察者。
    • 观察者订阅主题。
    • 当主题状态改变时,所有观察者都会收到更新通知。

程序运行结果

运行程序后输出如下:

天气宝App 收到了最新天气:晴天
气象通App 收到了最新天气:晴天
天气宝App 收到了最新天气:下雨
气象通App 收到了最新天气:下雨
气象通App 收到了最新天气:大风

可以看到:

  • 两个App订阅后,天气更新时都会收到通知。
  • 取消天气宝App的订阅后,只有气象通App收到通知。

优缺点

优点
  1. 松耦合设计
    • 主题和观察者通过接口交互,方便扩展和维护。
  2. 动态订阅机制
    • 可随时添加或移除观察者。
  3. 统一通知
    • 通知逻辑集中管理,简单直观。
缺点
  1. 性能开销
    • 如果观察者过多,通知过程可能带来性能问题。
  2. 依赖复杂
    • 观察者之间可能产生隐式依赖关系,增加调试难度。

应用场景

  1. 消息推送系统
    比如新闻网站向订阅用户推送最新动态。

  2. 实时数据更新
    数据变化时需要更新多个UI组件。

  3. 事件监听机制
    游戏中角色状态改变时通知其他玩家或系统。


总结

观察者模式是一个简单却功能强大的模式,它通过“发布-订阅”机制解耦了对象之间的依赖,使得代码更加灵活和易维护。在C++中,我们可以通过抽象接口和容器来实现观察者模式,并根据需求灵活扩展。

通过本文的天气预报示例,相信你已经掌握了观察者模式的核心概念及其实现方法!


http://www.kler.cn/a/399981.html

相关文章:

  • hadoop3.x 新特性
  • 模型的评估指标——IoU、混淆矩阵、Precision、Recall、P-R曲线、F1-score、mAP、AP、AUC-ROC
  • “乐鑫组件注册表”简介
  • 华为ensp实验二--mux vlan的应用
  • 计算机视觉和机器人技术中的下一个标记预测与视频扩散相结合
  • Ubuntu 18.04 配置sources.list源文件(无法安全地用该源进行更新,所以默认禁用该源)
  • 113页PPT制造业研发工艺协同及制造一体化
  • 四十、Python(pytest框架-下)
  • github进不去解决办法-误打误撞进去了
  • Redis GEO 功能解析
  • Spring Cloud Ribbon 实现“负载均衡”的详细配置说明
  • Stable Diffusion概要讲解
  • Jenkins的pipeline Script的 每个组件的详细讲解
  • LangChain学习--LangChain-chatchat代码研读
  • 2024年09月CCF-GESP编程能力等级认证Python编程二级真题解析
  • 爬虫——数据解析与提取
  • 高阶C语言之六:程序环境和预处理
  • 解决 IDEA 修改代码重启不生效的问题
  • 自动驾驶系列—面向自动驾驶的模型迭代:工具、平台与最佳实践
  • 矩阵的对角化特征值分解
  • 【网络云计算】2024第46周小测第2次-Shell编程类简要解析
  • 刘艳兵-DBA044-关于cardinality的描述,正确的是?
  • .NET 通过模块和驱动收集本地EDR的工具
  • org.springframework.context.support.ApplicationListenerDetector 详细介绍
  • Thinkphp-Laravel在线教育系统设计与实现us5uu
  • jenkins使用cli发行uni-app到h5