欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > ​【C++设计模式】第二十三篇:观察者模式(Observer)

​【C++设计模式】第二十三篇:观察者模式(Observer)

2025/3/17 1:35:49 来源:https://blog.csdn.net/JuicyActiveGilbert/article/details/146196315  浏览:    关键词:​【C++设计模式】第二十三篇:观察者模式(Observer)

注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。

事件驱动的订阅通知机制


1. 模式定义与用途

核心思想

  • 观察者模式:定义一种一对多依赖关系,当一个对象(主题)状态改变时,所有依赖它的对象(观察者)​自动收到通知并更新
    ​- 关键用途
    1.​解耦发布者与订阅者:主题无需知道观察者的具体实现。
    ​2.实时通知:支持动态添加或移除观察者。
    ​3.事件驱动架构:适用于GUI事件处理、数据监控、消息队列等场景。

经典场景

  • 股票价格变动通知多个交易终端。
  • 用户界面控件状态同步(如按钮点击触发面板更新)。
  • 传感器数据监控与报警系统。

2. 模式结构解析

UML类图

+---------------------+          +---------------------+  
|       Subject        |          |      Observer       |  
+---------------------+          +---------------------+  
| + attach(o: Observer)|          | + update(): void    |  
| + detach(o: Observer)|          +---------------------+  
| + notify()           |                    ^  
+---------------------+                    |  ^                                |  |                        +-------+-------+  |                        |               |  
+---------------------+    +-------------------+ +-------------------+  
|    ConcreteSubject  |    | ConcreteObserverA | | ConcreteObserverB |  
+---------------------+    +-------------------+ +-------------------+  
| + getState()        |    | + update()        | | + update()        |  
| + setState()        |    +-------------------+ +-------------------+  
+---------------------+  

角色说明

  1. Subject:主题接口,管理观察者列表,提供订阅/取消订阅方法。
  2. ConcreteSubject:具体主题,存储状态并在状态变化时通知观察者。
  3. Observer:观察者接口,定义更新方法update()
  4. ConcreteObserver:具体观察者,实现更新逻辑。

3. 现代C++实现示例

场景:股票价格变动通知系统

​步骤1:定义主题与观察者接口
#include <iostream>  
#include <vector>  
#include <memory>  
#include <unordered_set>  // 前向声明  
class StockObserver;  // 主题接口  
class StockSubject {  
public:  virtual ~StockSubject() = default;  virtual void attach(std::shared_ptr<StockObserver> observer) = 0;  virtual void detach(std::shared_ptr<StockObserver> observer) = 0;  virtual void notify() = 0;  
};  // 观察者接口  
class StockObserver : public std::enable_shared_from_this<StockObserver> {  
public:  virtual ~StockObserver() = default;  virtual void update(double price) = 0;  
};  
步骤2:实现具体主题(股票)
class Stock : public StockSubject {  
public:  Stock(const std::string& symbol) : symbol_(symbol), price_(0.0) {}  void setPrice(double price) {  price_ = price;  notify();  }  void attach(std::shared_ptr<StockObserver> observer) override {  observers_.insert(observer);  }  void detach(std::shared_ptr<StockObserver> observer) override {  observers_.erase(observer);  }  void notify() override {  for (auto& observer : observers_) {  observer->update(price_);  }  }  private:  std::string symbol_;  double price_;  std::unordered_set<std::shared_ptr<StockObserver>> observers_;  
};  
步骤3:实现具体观察者(交易终端)​
class TradingTerminal : public StockObserver {  
public:  TradingTerminal(const std::string& name) : name_(name) {}  void update(double price) override {  std::cout << "终端 [" << name_ << "] 收到报价: $" << price << "\n";  if (price > alertThreshold_) {  std::cout << "警告:价格超过阈值!\n";  }  }  void setAlertThreshold(double threshold) {  alertThreshold_ = threshold;  }  private:  std::string name_;  double alertThreshold_ = 100.0;  
};  
步骤4:客户端代码
int main() {  // 创建股票与观察者  auto appleStock = std::make_shared<Stock>("AAPL");  auto terminal1 = std::make_shared<TradingTerminal>("终端1");  auto terminal2 = std::make_shared<TradingTerminal>("终端2");  terminal2->setAlertThreshold(150.0);  // 订阅股票价格  appleStock->attach(terminal1);  appleStock->attach(terminal2);  // 更新价格并触发通知  appleStock->setPrice(120.5);  /* 输出:  终端 [终端1] 收到报价: $120.5  警告:价格超过阈值!  终端 [终端2] 收到报价: $120.5  */  // 取消订阅终端2  appleStock->detach(terminal2);  appleStock->setPrice(160.0);  /* 输出:  终端 [终端1] 收到报价: $160  警告:价格超过阈值!  */  
}  

4. 应用场景示例

场景1:GUI事件处理

class Button {  
public:  void addListener(std::shared_ptr<ButtonListener> listener) {  listeners_.push_back(listener);  }  void click() {  // 触发点击事件  for (auto& listener : listeners_) {  listener->onClick();  }  }  private:  std::vector<std::shared_ptr<ButtonListener>> listeners_;  
};  class LoggingListener : public ButtonListener {  
public:  void onClick() override {  std::cout << "按钮被点击,记录日志\n";  }  
};  

场景2:气象站数据监控

class WeatherStation : public Subject {  
public:  void setTemperature(double temp) {  temperature_ = temp;  notify();  }  
};  class PhoneApp : public Observer {  
public:  void update(double temp) override {  std::cout << "手机APP更新温度: " << temp << "°C\n";  }  
};  

5. 优缺点分析

​优点​缺点
松耦合设计,主题与观察者独立演化观察者可能收到不相关通知(需过滤逻辑)
支持动态订阅机制链式触发可能导致性能问题(级联更新)
简化事件分发逻辑需注意内存泄漏(观察者未正确注销)

6. 调试与优化策略

调试技巧(VS2022)​

1. ​验证通知触发:
  • notify()方法中设置断点,检查观察者列表是否正确更新。
2. 跟踪观察者状态:
  • 使用​内存诊断工具确保观察者对象在注销后被正确释放。

​性能优化

1. 批量通知:
  • 合并多次状态变更,延迟发送通知(如防抖处理)。
void Stock::setPrice(double price) {  price_ = price;  if (needNotify_) {  // 防抖逻辑  notify();  needNotify_ = false;  }  
}  
2. 异步通知:
#include <future>  
void Stock::notify() {  std::async(std::launch::async, [this] {  for (auto& observer : observers_) {  observer->update(price_);  }  });  
}  

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词