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

C++设计模式之行为型模式:观察者模式(Observer)

观察者模式(Observer)是行为型设计模式的一种,它定义了对象之间的一对多依赖关系,当一个对象(被观察者)的状态发生变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。这种模式也被称为“发布-订阅”模式,广泛应用于事件处理、消息通知等场景。

一、核心思想与角色

观察者模式的核心是“状态变化通知”,通过解耦被观察者和观察者,实现灵活的消息传递机制。其核心角色如下:

角色名称核心职责
抽象被观察者(Subject)定义被观察者的接口,提供添加、移除观察者和通知所有观察者的方法。
具体被观察者(ConcreteSubject)实现抽象被观察者接口,存储状态,状态变化时调用通知方法。
抽象观察者(Observer)定义观察者的接口,声明更新方法(当被观察者状态变化时被调用)。
具体观察者(ConcreteObserver)实现抽象观察者接口,在更新方法中响应被观察者的状态变化。

核心思想:被观察者维护一个观察者列表,状态变化时主动通知所有观察者;观察者被动接收通知并执行相应操作,两者通过抽象接口交互,实现松耦合。

二、实现示例(气象站与显示设备)

假设我们需要设计一个气象站系统:气象站(被观察者)收集温度、湿度数据,多个显示设备(观察者,如手机APP、控制台显示器)实时显示这些数据。使用观察者模式可实现数据变化时自动更新所有显示设备:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>// 1. 抽象观察者
class Observer {
public:// 纯虚方法:更新数据(温度、湿度)virtual void update(float temperature, float humidity) = 0;virtual ~Observer() = default;
};// 2. 抽象被观察者
class Subject {
public:// 添加观察者virtual void registerObserver(Observer* observer) = 0;// 移除观察者virtual void removeObserver(Observer* observer) = 0;// 通知所有观察者virtual void notifyObservers() = 0;virtual ~Subject() = default;
};// 3. 具体被观察者:气象站
class WeatherStation : public Subject {
private:std::vector<Observer*> observers; // 观察者列表float temperature;                // 温度float humidity;                   // 湿度public:WeatherStation() : temperature(0.0f), humidity(0.0f) {}// 添加观察者到列表void registerObserver(Observer* observer) override {observers.push_back(observer);}// 从列表移除观察者void removeObserver(Observer* observer) override {auto it = std::find(observers.begin(), observers.end(), observer);if (it != observers.end()) {observers.erase(it);}}// 通知所有观察者(传递当前状态)void notifyObservers() override {for (Observer* observer : observers) {observer->update(temperature, humidity);}}// 气象站数据更新(外部调用,如传感器采集)void setMeasurements(float temp, float hum) {temperature = temp;humidity = hum;std::cout << "\n气象站数据更新:温度 " << temp << "℃,湿度 " << hum << "%" << std::endl;notifyObservers(); // 数据更新后通知观察者}
};// 3. 具体观察者1:手机APP显示器
class PhoneDisplay : public Observer {
private:std::string name; // 设备名称public:PhoneDisplay(const std::string& n) : name(n) {}// 接收更新并显示void update(float temperature, float humidity) override {std::cout << name << " 显示:当前温度 " << temperature << "℃,湿度 " << humidity << "%" << std::endl;}
};// 3. 具体观察者2:控制台显示器
class ConsoleDisplay : public Observer {
public:// 接收更新并显示(带详细信息)void update(float temperature, float humidity) override {std::cout << "控制台显示:温度 " << temperature << "℃,湿度 " << humidity << "% | "<< (temperature > 30 ? "天气炎热" : "温度适宜") << std::endl;}
};// 客户端代码:组装系统并测试
int main() {// 创建被观察者(气象站)WeatherStation* station = new WeatherStation();// 创建观察者(显示设备)Observer* phone1 = new PhoneDisplay("小明的手机");Observer* phone2 = new PhoneDisplay("小红的手机");Observer* console = new ConsoleDisplay();// 注册观察者station->registerObserver(phone1);station->registerObserver(phone2);station->registerObserver(console);// 气象站更新数据(触发通知)station->setMeasurements(25.5f, 60.0f);// 移除一个观察者(小红的手机)station->removeObserver(phone2);std::cout << "\n--- 移除小红的手机后 ---" << std::endl;// 再次更新数据station->setMeasurements(32.0f, 50.0f);// 释放资源delete console;delete phone2;delete phone1;delete station;return 0;
}

三、代码解析

  1. 抽象观察者(Observer)
    定义update()纯虚方法,声明观察者接收通知后应执行的操作,参数为被观察者的状态数据(温度、湿度)。

  2. 抽象被观察者(Subject)
    定义registerObserver()(添加观察者)、removeObserver()(移除观察者)和notifyObservers()(通知观察者)接口,规范被观察者的行为。

  3. 具体被观察者(WeatherStation)

    • 维护observers列表存储所有注册的观察者。
    • setMeasurements()方法更新气象数据,并调用notifyObservers()通知所有观察者。
    • notifyObservers()遍历观察者列表,调用每个观察者的update()方法传递最新状态。
  4. 具体观察者

    • PhoneDisplay:实现update()方法,简单显示温度和湿度。
    • ConsoleDisplay:实现update()方法,除显示数据外,还添加了天气评价(如“天气炎热”)。
      两者都只关注如何处理接收到的状态,无需知道被观察者的具体类型。
  5. 客户端使用
    客户端创建被观察者和观察者,通过registerObserver()建立关联;当被观察者状态变化时,所有注册的观察者自动收到通知并更新。

四、核心优势与适用场景

优势
  1. 松耦合:被观察者无需知道观察者的具体类型和数量,只需通过抽象接口交互,一方变化不影响另一方。
  2. 动态关联:可在运行时动态添加或移除观察者(如示例中移除“小红的手机”),灵活性高。
  3. 广播通信:被观察者状态变化时,自动通知所有相关观察者,无需逐个调用。
  4. 单一职责:被观察者专注于状态管理,观察者专注于状态处理,符合单一职责原则。
适用场景
  1. 事件驱动系统:如GUI事件(按钮点击、窗口关闭)、消息队列通知。
  2. 数据实时更新:如股票行情显示、气象数据监控、实时监控系统。
  3. 发布-订阅模型:如微信公众号、邮件订阅、消息推送服务。
  4. 状态变化需要多方响应:当一个对象的变化需要触发多个其他对象的操作时。

五、与其他模式的区别

模式核心差异点
观察者模式一对多依赖,被观察者主动通知观察者,强调“状态变化通知”。
中介者模式多对多交互通过中介者集中处理,强调“交互集中控制”。
发布-订阅模式观察者模式的变种,通过消息队列/主题实现松耦合,通常异步通信。
职责链模式请求沿链传递,由一个处理者处理,强调“请求分发”。

六、实践建议

  1. 避免循环依赖:观察者和被观察者之间应避免双向依赖,防止通知时出现无限循环。
  2. 处理通知顺序:若观察者更新有先后顺序要求,需在被观察者中明确通知顺序,或使用优先级队列。
  3. 支持异步通知:对于耗时的观察者操作,可使用异步通知(如多线程)避免阻塞被观察者。
  4. 提供拉取模式:除示例中的“推模式”(被观察者主动传递数据),还可支持“拉模式”(观察者按需从被观察者获取数据),减少不必要的数据传递。
  5. 清理资源:观察者销毁前需从被观察者中移除自己,避免访问已销毁对象(悬垂指针)。

观察者模式的核心价值在于“实现对象间的解耦通信”,它通过定义清晰的通知机制,使状态变化能自动传递给所有依赖对象,是构建事件驱动和实时响应系统的理想选择。在需要多方响应同一状态变化的场景中,观察者模式能显著提高系统的灵活性和可扩展性。

http://www.dtcms.com/a/469840.html

相关文章:

  • 指数分布:从理论到机器学习应用
  • (Python)终端着色基础(八色样式码):一般(0-9)十之用三四,更有传说『53上划线』,众多终端不实现
  • webman项目开机自启动
  • 男和女做暖暖网站官方正版浏览器
  • 网站收录量是什么意思网站改版 信科网络
  • PDM:产品数据的智能枢纽,驱动企业高效创新
  • Redis重大版本演进全解析:从2.6到7.0
  • mysql高可用架构之MHA部署(二)VIP漂移(保姆级)
  • 【从零开始java学习|第二十二篇】集合进阶之collection
  • 活动回顾 | AutoMQ 新加坡 TOKEN2049:展示高效 Web3 数据流基础设施
  • 多字节串口收发IP设计(四)串口接收模块设计及联合仿真(含源码)
  • 封装相关学习
  • 成都网站优化方案wordpress cms主题教程
  • 网络原理基础
  • aws s3设置跨域,s3配置预签名,aws 配置文件上传
  • 18芯城网站开发案例国内简约网站设计
  • 网站开发用什么字体一般域名的作用
  • 『 QT 』Hello World控件实现指南
  • 【CF】Day148——Codeforces Round 1057 (Div. 2) CD (非退化凸多边形的分类讨论 | 破环成链动态规划)
  • 网站建设教程金旭亮wordpress自动加p标签
  • 使用C#代码将ODT转换为PDF文件
  • 【网络编程】详解 IP 协议:报头字段、路由器功能、网段划分和分片传输
  • 大模型微调 SFTTrainer 数据处理与训练器配置解析(116)
  • gtest简单应用
  • 访答知识库,企业知识库,访答浏览器,Al编辑器,RAG,Pdf转word。个人知识库,访答RAG,云知识库,私有知识库……
  • 通过企业画册宣传_网络网站建设_新闻媒体合作等方式_企业营销网站制作
  • BERT相关知识自测
  • 【完整源码+数据集+部署教程】 真菌孢子图像分割系统源码&数据集分享 [yolov8-seg-convnextv2等50+全套改进创新点发刊_一键训练
  • 遵义市网站制作如何申请域名网站注册
  • GitHub 热榜项目 - 日榜(2025-10-11)