你是一名C++程序员,负责开发公司的核心的股票交易系统,老板见到你都得喊一声哥,系统的核心是一个Stock类,存储股票的实时价格:
class Stock {
private:
std::string symbol_;
double price_;
public:
void setPrice(double price) { price_ = price; }
double getPrice() const { return price_; }
};
现在有三个模块需要关注股价变化:交易界面要显示最新价格;价格超过阈值时预警模块要发出警报;每次价格变动日志模块要记录日志。
现在问题来了:当股价变化时,这三个模块怎么知道?
轮询检查
你的第一个想法很直接:让每个模块不停地查询股价。
// 交易界面的代码
void TradingUI::run() {
double lastPrice = 0;
while (true) {
double currentPrice = stock_->getPrice();
if (currentPrice != lastPrice) {
updateDisplay(currentPrice);
lastPrice = currentPrice;
}
sleep(1); // 每1毫秒检查一次
}
}
预警模块和日志模块也写了类似的代码,各自不停地轮询。
你运行了一下,功能是对的,但很快你老板见到你不叫哥了。
打开任务管理器,CPU占用率飙升,三个模块同时轮询,更糟的是,如果股价在两次轮询之间变化了两次(比如100→105→102),中间那次105的变化就丢失了。
这种方法既浪费资源,又可能丢失事件。
你需要一种更好的方法:让Stock主动通知关心它的模块,而不是让模块来问。
硬编码回调
聪明的你很快想到了办法:在Stock内部直接调用需要通知的模块。
class Stock {
private:
double price_;
TradingUI* ui_;
AlertSystem* alert_;
Logger* logger_;
public:
void setPrice(double price) {
price_ = price;
// 直接通知各个模块
ui_->onPriceChanged(price);
alert_->onPriceChanged(price);
logger_->onPriceChanged(price);
}
};
这下不用轮询了!股价一变,三个模块立刻收到通知。
你测试了一下,完美,CPU占用率降到几乎为零,也不会丢失任何变化。
但一周后,问题来了。
产品经理说:"我们要加一个新功能——价格图表模块,也需要监听股价变化。"
你打开Stock类,加了一行:
void setPrice(double price) {
price_ = price;
ui_->onPriceChanged(price);
alert_->onPriceChanged(price);
logger_->onPriceChanged(price);
chart_->onPriceChanged(price); // 新加的
}
又过了一周,产品经理说:"预警模块下线了,不需要通知它了。",WTF,你又打开Stock类,删掉了一行。
你开始感到不对劲:每次增删一个监听者,都要修改Stock类的代码。
Stock是核心类,改动它有风险,而且它现在"知道"了所有监听者的存在,耦合度太高了。
问题又暴露了:Stock和监听者之间是硬编码的依赖,无法动态增删。
你需要一种更更优的方法:让Stock不知道具体有谁在监听,但能通知所有人。
观察者列表
你灵机一动一拍大腿:用一个列表来存储所有监听者!
首先,定义一个统一的接口:
class IPriceObserver {
public:
virtual void onPriceChanged(double newPrice) = 0;
virtual ~IPriceObserver() = default;
};
然后,让所有监听者实现这个接口:
class TradingUI : public IPriceObserver {
public:
void onPriceChanged(double newPrice) override {
updateDisplay(newPrice);
}
};
class AlertSystem : public IPriceObserver {
public:
void onPriceChanged(double newPrice) override {
if (newPrice > threshold_) triggerAlert();
}
};
最后,Stock类只维护一个观察者列表:
class Stock {
private:
double price_;
std::vector<IPriceObserver*> observers_;
public:
void addObserver(IPriceObserver* observer) {
observers_.push_back(observer);
}
void removeObserver(IPriceObserver* observer) {
// 从列表中移除
observers_.erase(
std::remove(observers_.begin(), observers_.end(), observer),
observers_.end()
);
}
void setPrice(double price) {
price_ = price;
// 通知所有观察者
for (auto* observer : observers_) {
observer->onPriceChanged(price);
}
}
};
你测试了一下:
Stock stock;
TradingUI ui;
AlertSystem alert;
Logger logger;
stock.addObserver(&ui);
stock.addObserver(&alert);
stock.addObserver(&logger);
stock.setPrice(100.5); // 三个模块同时收到通知!
// 下线预警模块
stock.removeObserver(&alert);
stock.setPrice(101.0); // 只有ui和logger收到通知
完美!现在增删监听者不需要修改Stock类的代码了。
但随着系统规模扩大,你又发现了一个新的麻烦。
多对多的监听关系变得复杂
系统不只有Stock一个被观察者了,现在有三种数据源:
class Stock { ... }; // 股价
class Index { ... }; // 大盘指数
class Exchange { ... }; // 汇率
每种数据源都要定义自己的观察者接口:
class IPriceObserver { virtual void onPriceChanged(double) = 0; };
class IIndexObserver { virtual void onIndexChanged(double) = 0; };
class IExchangeObserver { virtual void onExchangeChanged(double) = 0; };
而AlertSystem需要监听所有这三种数据——它得实现三个接口:
class AlertSystem : public IPriceObserver,
public IIndexObserver,
public IExchangeObserver {
void onPriceChanged(double price) override { ... }
void onIndexChanged(double index) override { ... }
void onExchangeChanged(double rate) override { ... }
};
注册时,AlertSystem还得知道每个被观察者的存在:
stock.addObserver(&alert);
index.addObserver(&alert);
exchange.addObserver(&alert);
问题又又又暴露了:
- 每新增一种数据源,就要新增一个接口,
AlertSystem就要多实现一个接口 AlertSystem必须知道所有被观察者的存在,耦合度高- 如果
TradingUI也要监听这三种数据,同样的代码再写一遍
你揪着头上硕果仅存的几根头发思考:有没有办法统一所有的事件,让观察者不需要知道被观察者的具体类型?
你拍着已经肿了的大腿又想到一个巧妙的办法:引入一个中间人,让双方都只和中间人打交道。
class EventBus {
private:
// 事件名 → 回调函数列表
std::map<std::string, std::vector<std::function<void(double)>>> subscribers_;
public:
// 订阅事件
void subscribe(const std::string& event, std::function<void(double)> callback) {
subscribers_[event].push_back(callback);
}
// 发布事件
void publish(const std::string& event, double data) {
if (subscribers_.find(event) != subscribers_.end()) {
for (auto& callback : subscribers_[event]) {
callback(data);
}
}
}
};
// 全局事件总线
EventBus g_eventBus;
现在,Stock不需要知道谁在监听:
class Stock {
private:
double price_;
public:
void setPrice(double price) {
price_ = price;
g_eventBus.publish("stock.price.changed", price); // 只管发布
}
};
监听者也不需要知道Stock的存在,甚至不需要实现任何接口:
这种"一个对象状态变化,自动通知所有依赖它的对象"的模式,就是所谓的观察者模式(Observer Pattern)。
评论区
登录后即可参与讨论
立即登录