观察者模式(Observer Pattern)是行为型设计模式中的事件通知专家,它定义了对象间一种一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动收到通知并更新。这种模式实现了发布-订阅机制,是事件处理系统的核心基础。本文将深入探索观察者模式的核心思想、实现技巧以及在C++中的高效实践。
为什么需要观察者模式?
在软件开发中,对象状态变化需要通知其他对象:
GUI中的按钮点击事件处理
股票价格变动通知交易系统
游戏引擎中的碰撞检测通知
分布式系统中的服务状态更新
物联网设备状态同步
直接的对象间通知会导致:
紧耦合:对象间存在复杂依赖关系
维护困难:添加/删除观察者需修改主题代码
性能问题:同步通知阻塞主线程
扩展性差:难以动态添加新观察者类型
观察者模式通过解耦主题和观察者解决了这些问题。
观察者模式的核心概念
模式结构解析
[主题] ← [具体主题]|| 通知▼
[观察者] ← [具体观察者]
关键角色定义
主题接口(Subject)
提供注册、删除和通知观察者的接口
维护观察者列表
具体主题(Concrete Subject)
实现主题接口
存储状态数据
状态变化时通知观察者
观察者接口(Observer)
定义更新接口
接收主题通知
具体观察者(Concrete Observer)
实现观察者接口
维护对主题的引用
同步自身状态与主题状态
C++实现:股票交易通知系统
实现一个股票价格变动通知系统,展示观察者模式的实际应用:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <algorithm>
#include <mutex>
#include <thread>
#include <chrono>
#include <random>// ================= 观察者接口 =================
class StockObserver {
public:virtual ~StockObserver() = default;virtual void update(const std::string& symbol, double price) = 0;virtual std::string getName() const = 0;
};// ================= 主题接口 =================
class StockMarket {
public:virtual ~StockMarket() = default;virtual void registerObserver(const std::string& symbol, std::shared_ptr<StockObserver> observer) = 0;virtual void removeObserver(const std::string& symbol, const std::string& observerName) = 0;virtual void notifyObservers(const std::string& symbol) = 0;virtual void setPrice(const std::string& symbol, double price) = 0;virtual double getPrice(const std::string& symbol) const = 0;
};// ================= 具体主题:股票交易所 =================
class StockExchange : public StockMarket {
public:void registerObserver(const std::string& symbol, std::shared_ptr<StockObserver> observer) override {std::lock_guard lock(mutex_);observers_[symbol].push_back(observer);std::cout << observer->getName() << " 注册监听股票: " << symbol << std::endl;}void removeObserver(const std::string& symbol, const std::string& observerName) override {std::lock_guard lock(mutex_);auto& list = observers_[symbol];list.erase(std::remove_if(list.begin(), list.end(),[&](const auto& obs) {return obs->getName() == observerName;}),list.end());std::cout << observerName << " 取消监听股票: " << symbol << std::endl;}void notifyObservers(const std::string& symbol) override {std::vector<std::shared_ptr<StockObserver>> currentObservers;{std::lock_guard lock(mutex_);if (observers_.find(symbol) == observers_.end()) return;currentObservers = observers_[symbol];}double currentPrice = getPrice(symbol);for (auto& observer : currentObservers) {observer->update(symbol, currentPrice);}}void setPrice(const std::string& symbol, double price) override {{std::lock_guard lock(mutex_);stockPrices_[symbol] = price;}std::cout << "\n=== " << symbol << " 价格更新: " << price << " ===" << std::endl;notifyObservers(symbol);}double getPrice(const std::string& symbol) const override {std::lock_guard lock(mutex_);auto it = stockPrices_.find(symbol);return it != stockPrices_.end() ? it->second : 0.0;}private:mutable std::mutex mutex_;std::unordered_map<std::string, double> stockPrices_;std::unordered_map<std::string, std::vector<std::shared_ptr<StockObserver>>> observers_;
};// ================= 具体观察者:交易机器人 =================
class TradingBot : public StockObserver {
public:TradingBot(const std::string& name, double buyThreshold, double sellThreshold): name_(name), buyThreshold_(buyThreshold), sellThreshold_(sellThreshold) {}void update(const std::string& symbol, double price) override {std::cout << "🤖 " << name_ << " 收到 " << symbol << " 更新: " << price << std::endl;// 交易决策逻辑if (price <= buyThreshold_ && !holding_) {buy(symbol, price);} else if (price >= sellThreshold_ && holding_) {sell(symbol, price);}}std::string getName() const override { return name_; }private:void buy(const std::string& symbol, double price) {std::cout << "买入 " << symbol << " @ " << price << std::endl;holding_ = true;lastBuyPrice_ = price;}void sell(const std::string& symbol, double price) {double profit = price - lastBuyPrice_;std::cout << "卖出 " << symbol << " @ " << price << " | 利润: " << profit << std::endl;holding_ = false;}std::string name_;double buyThreshold_;double sellThreshold_;bool holding_ = false;double lastBuyPrice_ = 0.0;
};// ================= 具体观察者:价格警报器 =================
class PriceAlert : public StockObserver {
public:PriceAlert(const std::string& name, double alertPrice, bool above): name_(name), alertPrice_(alertPrice), above_(above) {}void update(const std::string& symbol, double price) override {if ((above_ && price >= alertPrice_) || (!above_ && price <= alertPrice_)) {std::cout << name_ << " 警报: " << symbol << " 价格 " << (above_ ? "突破" : "跌破") << " " << alertPrice_ << " (当前: " << price << ")" << std::endl;}}std::string getName() const override { return name_; }private:std::string name_;double alertPrice_;bool above_;
};// ================= 具体观察者:移动应用通知 =================
class MobileApp : public StockObserver {
public:explicit MobileApp(const std::string& user) : user_(user) {}void update(const std::string& symbol, double price) override {std::cout << "[" << user_ << "] 股票更新: " << symbol << " 当前价格: " << price << std::endl;}std::string getName() const override { return "MobileApp-" + user_; }private:std::string user_;
};// ================= 股票价格模拟器 =================
class StockPriceSimulator {
public:StockPriceSimulator(StockMarket& market, const std::string& symbol, double startPrice, double volatility): market_(market), symbol_(symbol), currentPrice_(startPrice), volatility_(volatility), running_(false) {}void start() {running_ = true;thread_ = std::thread(&StockPriceSimulator::run, this);}void stop() {running_ = false;if (thread_.joinable()) thread_.join();}void run() {std::random_device rd;std::mt19937 gen(rd());std::normal_distribution<> dist(0.0, volatility_);while (running_) {// 随机波动double change = dist(gen);currentPrice_ += currentPrice_ * change;// 确保价格不为负if (currentPrice_ < 0.1) currentPrice_ = 0.1;// 更新市场market_.setPrice(symbol_, currentPrice_);// 暂停std::this_thread::sleep_for(std::chrono::seconds(1));}}private:StockMarket& market_;std::string symbol_;double currentPrice_;double volatility_;bool running_;std::thread thread_;
};// ================= 客户端代码 =================
int main() {// 创建股票交易所auto exchange = std::make_shared<StockExchange>();// 初始化股票价格exchange->setPrice("AAPL", 150.0);exchange->setPrice("GOOGL", 2800.0);exchange->setPrice("TSLA", 700.0);// 创建观察者auto bot1 = std::make_shared<TradingBot>("保守机器人", 145.0, 160.0);auto bot2 = std::make_shared<TradingBot>("激进机器人", 155.0, 170.0);auto alert1 = std::make_shared<PriceAlert>("AAPL警报", 160.0, true);auto alert2 = std::make_shared<PriceAlert>("TSLA警报", 750.0, true);auto mobileUser1 = std::make_shared<MobileApp>("张三");auto mobileUser2 = std::make_shared<MobileApp>("李四");// 注册观察者exchange->registerObserver("AAPL", bot1);exchange->registerObserver("AAPL", bot2);exchange->registerObserver("AAPL", alert1);exchange->registerObserver("AAPL", mobileUser1);exchange->registerObserver("GOOGL", mobileUser1);exchange->registerObserver("TSLA", alert2);exchange->registerObserver("TSLA", mobileUser2);// 启动价格模拟器StockPriceSimulator aaplSimulator(*exchange, "AAPL", 150.0, 0.02);StockPriceSimulator tslaSimulator(*exchange, "TSLA", 700.0, 0.03);aaplSimulator.start();tslaSimulator.start();// 模拟运行一段时间std::this_thread::sleep_for(std::chrono::seconds(10));// 动态添加新观察者std::cout << "\n===== 添加新观察者 =====" << std::endl;auto newAlert = std::make_shared<PriceAlert>("AAPL下跌警报", 140.0, false);exchange->registerObserver("AAPL", newAlert);// 继续运行std::this_thread::sleep_for(std::chrono::seconds(5));// 停止模拟aaplSimulator.stop();tslaSimulator.stop();// 移除部分观察者std::cout << "\n===== 移除观察者 =====" << std::endl;exchange->removeObserver("AAPL", "激进机器人");exchange->removeObserver("TSLA", "MobileApp-李四");return 0;
}
观察者模式的五大优势
解耦主题与观察者
// 主题不知道观察者具体类型 void notifyObservers() {for (auto& obs : observers_) {obs->update(data); // 仅依赖接口} }
动态添加观察者
// 运行时注册新观察者 exchange->registerObserver("AAPL", newTradingBot);
支持广播通信
// 通知所有订阅者 void setPrice(const string& symbol, double price) {stockPrices_[symbol] = price;notifyObservers(symbol); // 广播通知 }
事件驱动架构
// 响应状态变化 void onPriceChange() {market_->setPrice(symbol_, newPrice); // 触发事件 }
多播通信控制
// 按主题通知 void notifyObservers(const string& symbol) {// 只通知订阅该symbol的观察者 }
观察者模式的高级应用
1. 事件总线系统
class EventBus {
public:void subscribe(const string& eventType, shared_ptr<Observer> observer) {subscribers_[eventType].push_back(observer);}void unsubscribe(const string& eventType, const string& observerName) {auto& list = subscribers_[eventType];list.erase(remove_if(list.begin(), list.end(),[&](auto& obs) { return obs->getName() == observerName; }), list.end());}void publish(const string& eventType, const string& data) {if (subscribers_.find(eventType) == subscribers_.end()) return;for (auto& observer : subscribers_[eventType]) {observer->handleEvent(eventType, data);}}
};
2. 异步观察者
class AsyncNotifier {
public:void notify(shared_ptr<Observer> observer, const string& data) {queue_.push({observer, data});}void processNotifications() {while (!queue_.empty()) {auto [observer, data] = queue_.front();queue_.pop();observer->update(data);}}private:queue<pair<shared_ptr<Observer>, string>> queue_;
};class AsyncStockExchange : public StockExchange {void notifyObservers(const string& symbol) override {double price = getPrice(symbol);for (auto& observer : getObservers(symbol)) {asyncNotifier_.notify(observer, symbol, price);}}void processAsyncNotifications() {asyncNotifier_.processNotifications();}
};
3. 观察者优先级
class PriorityStockExchange : public StockExchange {void registerObserver(const string& symbol, shared_ptr<StockObserver> observer,int priority) {auto& list = observers_[symbol];list.insert(std::upper_bound(list.begin(), list.end(), priority, [](int prio, const auto& obs) { return prio > obs->getPriority(); }), observer);}void notifyObservers(const string& symbol) override {auto observers = getObservers(symbol);for (auto& observer : observers) {observer->update(symbol, getPrice(symbol));}}
};
观察者模式的应用场景
1. GUI事件处理
class Button {
public:void addClickListener(shared_ptr<ClickListener> listener) {clickListeners_.push_back(listener);}void click() {// UI逻辑...notifyClickListeners();}private:void notifyClickListeners() {for (auto& listener : clickListeners_) {listener->onClick(this);}}vector<shared_ptr<ClickListener>> clickListeners_;
};class LoginDialog {
public:LoginDialog() {loginButton_->addClickListener(make_shared<ClickListener>([this] {attemptLogin();}));}void attemptLogin() {// 登录逻辑...}
};
2. 游戏引擎事件系统
class GameEventSystem {
public:void subscribe(EventType type, shared_ptr<GameObject> obj) {subscribers_[type].push_back(obj);}void publish(EventType type, EventData data) {for (auto& subscriber : subscribers_[type]) {subscriber->handleEvent(type, data);}}
};class Player : public GameObject {void handleEvent(EventType type, EventData data) override {if (type == EventType::COLLISION) {auto& collData = static_cast<CollisionData&>(data);if (collData.other->isEnemy()) {takeDamage(collData.damage);}}}
};class PhysicsEngine {void detectCollision() {// 碰撞检测...eventSystem_.publish(EventType::COLLISION, collisionData);}
};
3. 配置变更通知
class ConfigManager {
public:void addChangeListener(shared_ptr<ConfigChangeListener> listener) {listeners_.push_back(listener);}void setValue(const string& key, const string& value) {config_[key] = value;notifyChangeListeners(key, value);}private:void notifyChangeListeners(const string& key, const string& value) {for (auto& listener : listeners_) {listener->onConfigChange(key, value);}}unordered_map<string, string> config_;vector<shared_ptr<ConfigChangeListener>> listeners_;
};class ThemeManager : public ConfigChangeListener {void onConfigChange(const string& key, const string& value) override {if (key == "theme") {applyTheme(value);}}
};
观察者模式与其他模式的关系
模式 | 关系 | 区别 |
---|---|---|
中介者 | 都管理对象间通信 | 中介者集中控制,观察者分布通知 |
发布-订阅 | 观察者的高级变体 | 发布-订阅通常解耦更强 |
责任链 | 都处理请求 | 责任链传递请求,观察者广播通知 |
备忘录 | 都可实现状态通知 | 备忘录保存状态,观察者响应状态变化 |
组合使用示例:
// 观察者 + 中介者
class ChatRoomMediator : public Mediator {void sendMessage(const string& msg, User* sender) override {for (auto user : users_) {if (user != sender) {user->receive(msg); // 观察者通知}}}
};
观察者模式的挑战与解决方案
挑战 | 解决方案 |
---|---|
观察者执行阻塞 | 使用异步通知或线程池 |
通知顺序依赖 | 实现优先级队列 |
内存泄漏风险 | 使用弱引用或自动注销机制 |
意外递归更新 | 实现更新标记和批处理 |
弱引用观察者示例:
class WeakObserver : public StockObserver {
public:void registerWith(weak_ptr<StockMarket> market) {market_ = market;}void update(const string& symbol, double price) override {if (auto market = market_.lock()) {// 安全访问}}private:weak_ptr<StockMarket> market_;
};
总结
观察者模式是现代软件架构的事件通信基石,它通过:
解耦设计:分离事件生产者和消费者
动态订阅:运行时添加/移除观察者
事件广播:高效通知多个订阅者
响应式编程:支持事件驱动架构
适用场景:
需要实现事件通知机制
需要解耦事件源和事件处理器
需要广播状态变化
需要动态管理订阅关系
"观察者模式不是简单的回调机制,而是将事件处理提升为系统架构。它是响应式系统的通信生命线。" — 设计模式实践者