1. 观察者模式的核心概念与应用场景
观察者模式(Observer Pattern)是设计模式中最常用的行为型模式之一,它定义了对象间一对多的依赖关系,当一个对象状态发生改变时,所有依赖它的对象都会自动收到通知并更新。这种模式在C++开发中尤为常见,特别是在需要实现松耦合的组件间通信时。
在金融交易系统中,我们经常需要处理这样的场景:当股票价格发生变化时,多个显示组件(如K线图、报价板、预警系统)需要同步更新。这正是观察者模式的典型应用。通过这种模式,价格数据源(被观察者)与各个显示组件(观察者)之间建立动态订阅关系,避免了硬编码的调用链。
注意:观察者模式与发布-订阅模式(Pub-Sub)有相似之处,但前者通常用于同一进程内的对象通信,后者则更多用于分布式系统间的消息传递。
观察者模式的核心参与者包括:
- Subject(被观察者):维护观察者列表,提供注册和注销接口,状态变化时通知观察者
- Observer(观察者):定义更新接口,供被观察者调用
- ConcreteSubject(具体被观察者):实现业务逻辑,状态改变时触发通知
- ConcreteObserver(具体观察者):实现更新逻辑,对被观察者状态变化做出响应
在C++中实现观察者模式时,我们通常需要考虑以下几个关键问题:
- 如何设计观察者的通知接口?
- 如何处理观察者的生命周期管理?
- 如何避免通知过程中的循环调用?
- 如何保证线程安全?
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. C++实现观察者模式的基本框架
2.1 基础接口设计
我们先来看一个最基本的观察者模式实现框架。在C++中,我们通常会使用抽象基类来定义观察者接口:
cpp复制// 观察者接口
class IObserver {
public:
virtual ~IObserver() = default;
virtual void Update(const std::string& message) = 0;
};
// 被观察者接口
class ISubject {
public:
virtual ~ISubject() = default;
virtual void Attach(IObserver* observer) = 0;
virtual void Detach(IObserver* observer) = 0;
virtual void Notify() = 0;
};
2.2 具体实现示例
下面是一个具体的股票价格监控系统的实现示例:
cpp复制// 具体被观察者 - 股票价格数据源
class StockPrice : public ISubject {
private:
std::vector<IObserver*> observers_;
double price_;
std::string symbol_;
public:
StockPrice(const std::string& symbol, double price)
: symbol_(symbol), price_(price) {}
void SetPrice(double price) {
if (price_ != price) {
price_ = price;
Notify(); // 价格变化时通知所有观察者
}
}
void Attach(IObserver* observer) override {
observers_.push_back(observer);
}
void Detach(IObserver* observer) override {
observers_.erase(
std::remove(observers_.begin(), observers_.end(), observer),
observers_.end());
}
void Notify() override {
std::string message = symbol_ + " price changed to " + std::to_string(price_);
for (auto observer : observers_) {
observer->Update(message);
}
}
};
// 具体观察者 - K线图显示
class KLineChart : public IObserver {
public:
void Update(const std::string& message) override {
std::cout << "KLineChart received update: " << message << std::endl;
// 这里实现实际的K线图更新逻辑
}
};
2.3 使用示例
cpp复制int main() {
StockPrice apple("AAPL", 150.0);
KLineChart chart1, chart2;
apple.Attach(&chart1);
apple.Attach(&chart2);
apple.SetPrice(152.5); // 两个K线图都会收到更新
apple.Detach(&chart1);
apple.SetPrice(153.0); // 只有chart2会收到更新
return 0;
}
3. 观察者模式的高级实现技巧
3.1 使用智能指针管理观察者生命周期
原始指针管理观察者存在内存泄漏风险,我们可以使用shared_ptr和weak_ptr来改进:
cpp复制class ISubject {
public:
virtual void Attach(std::shared_ptr<IObserver> observer) = 0;
virtual void Detach(std::shared_ptr<IObserver> observer) = 0;
// ...
};
class StockPrice : public ISubject {
private:
std::vector<std::weak_ptr<IObserver>> observers_;
// ...
void Notify() override {
auto it = observers_.begin();
while (it != observers_.end()) {
if (auto observer = it->lock()) {
observer->Update(message);
++it;
} else {
it = observers_.erase(it);
}
}
}
};
3.2 线程安全实现
在多线程环境中,我们需要确保观察者列表的操作是线程安全的:
cpp复制#include <mutex>
class StockPrice : public ISubject {
private:
std::vector<std::weak_ptr<IObserver>> observers_;
mutable std::mutex mutex_;
// ...
public:
void Attach(std::shared_ptr<IObserver> observer) override {
std::lock_guard<std::mutex> lock(mutex_);
observers_.emplace_back(observer);
}
void Detach(std::shared_ptr<IObserver> observer) override {
std::lock_guard<std::mutex> lock(mutex_);
observers_.erase(
std::remove_if(observers_.begin(), observers_.end(),
[&observer](const std::weak_ptr<IObserver>& wp) {
return wp.expired() || wp.lock() == observer;
}),
observers_.end());
}
void Notify() override {
std::vector<std::weak_ptr<IObserver>> observers_copy;
{
std::lock_guard<std::mutex> lock(mutex_);
observers_copy = observers_;
}
// ... 通知逻辑
}
};
3.3 事件过滤与优先级
有时我们需要对通知进行过滤或设置优先级:
cpp复制struct ObserverInfo {
std::weak_ptr<IObserver> observer;
int priority; // 优先级,数值越小优先级越高
std::function<bool(const Event&)> filter; // 事件过滤器
};
class StockPrice : public ISubject {
private:
std::vector<ObserverInfo> observers_;
// ...
void Notify() override {
Event event = GenerateEvent();
auto observers_copy = GetObserversCopy();
// 按优先级排序
std::sort(observers_copy.begin(), observers_copy.end(),
[](const ObserverInfo& a, const ObserverInfo& b) {
return a.priority < b.priority;
});
for (auto& info : observers_copy) {
if (auto observer = info.observer.lock()) {
if (!info.filter || info.filter(event)) {
observer->Update(event);
}
}
}
}
};
4. 观察者模式在金融交易系统中的应用实例
4.1 K线图实时更新实现
在金融交易系统中,K线图的实时更新是观察者模式的典型应用。下面我们实现一个更完整的K线图系统:
cpp复制// 定义金融事件类型
enum class EventType { PRICE_UPDATE, VOLUME_UPDATE, TRADE_EXECUTED };
struct FinancialEvent {
EventType type;
std::string symbol;
double price;
int volume;
// 其他相关字段...
};
// 金融数据源
class MarketDataFeed : public ISubject {
private:
std::vector<std::weak_ptr<IObserver>> observers_;
std::unordered_map<std::string, double> lastPrices_;
// ...
public:
void OnPriceUpdate(const std::string& symbol, double price) {
lastPrices_[symbol] = price;
FinancialEvent event{EventType::PRICE_UPDATE, symbol, price, 0};
Notify(event);
}
void Notify(const FinancialEvent& event) override {
auto observers_copy = GetObserversCopy();
for (auto& weak_observer : observers_copy) {
if (auto observer = weak_observer.lock()) {
observer->Update(event);
}
}
}
};
// 增强版K线图观察者
class AdvancedKLineChart : public IObserver {
private:
std::string symbol_;
std::vector<CandleStick> candles_;
public:
explicit AdvancedKLineChart(const std::string& symbol) : symbol_(symbol) {}
void Update(const FinancialEvent& event) override {
if (event.symbol == symbol_ && event.type == EventType::PRICE_UPDATE) {
UpdateCandle(event.price);
Render();
}
}
void UpdateCandle(double price) {
// 实现K线更新逻辑
auto now = std::chrono::system_clock::now();
// ... 根据时间窗口聚合价格数据
}
void Render() {
// 实现K线图渲染逻辑
// 可以使用Qt、OpenGL或其他图形库
}
};
4.2 交易预警系统实现
观察者模式也常用于实现交易预警系统:
cpp复制class PriceAlert : public IObserver {
private:
std::string symbol_;
double triggerPrice_;
bool isAbove_;
public:
PriceAlert(const std::string& symbol, double triggerPrice, bool isAbove)
: symbol_(symbol), triggerPrice_(triggerPrice), isAbove_(isAbove) {}
void Update(const FinancialEvent& event) override {
if (event.symbol == symbol_ && event.type == EventType::PRICE_UPDATE) {
bool triggered = isAbove_ ?
(event.price >= triggerPrice_) :
(event.price <= triggerPrice_);
if (triggered) {
std::cout << "ALERT: " << symbol_ << " price "
<< (isAbove_ ? "rose above " : "fell below ")
<< triggerPrice_ << " (current: " << event.price << ")\n";
// 可以触发邮件、短信通知等
}
}
}
};
4.3 多线程环境下的性能优化
在高频交易系统中,性能至关重要。我们可以采用以下优化策略:
- 批量通知:将多个更新合并为一个通知
- 无锁设计:使用原子操作或无锁队列
- 线程局部观察者列表:减少锁竞争
cpp复制class HighFrequencyMarketData : public ISubject {
private:
std::atomic<bool> notifying_{false};
moodycamel::ConcurrentQueue<std::weak_ptr<IObserver>> observersQueue_;
moodycamel::ConcurrentQueue<FinancialEvent> eventsQueue_;
public:
void Attach(std::shared_ptr<IObserver> observer) override {
observersQueue_.enqueue(observer);
}
void OnPriceUpdate(const std::string& symbol, double price) {
FinancialEvent event{EventType::PRICE_UPDATE, symbol, price, 0};
eventsQueue_.enqueue(event);
if (!notifying_.exchange(true)) {
// 启动通知线程
std::thread([this]() {
ProcessNotifications();
notifying_ = false;
}).detach();
}
}
private:
void ProcessNotifications() {
FinancialEvent event;
std::vector<std::weak_ptr<IObserver>> observers;
// 批量获取事件和观察者
while (eventsQueue_.try_dequeue(event)) {
std::weak_ptr<IObserver> observer;
while (observersQueue_.try_dequeue(observer)) {
observers.push_back(observer);
}
// 批量通知
for (auto& weak_observer : observers) {
if (auto observer = weak_observer.lock()) {
observer->Update(event);
}
}
}
}
};
5. 观察者模式的常见问题与解决方案
5.1 循环引用与内存泄漏
在使用智能指针时,不正确的使用可能导致循环引用:
cpp复制// 错误示例:导致循环引用
class Trader : public IObserver {
private:
std::shared_ptr<ISubject> subject_;
public:
Trader(std::shared_ptr<ISubject> subject) : subject_(subject) {
subject_->Attach(shared_from_this()); // 循环引用!
}
};
解决方案是使用weak_ptr打破循环:
cpp复制class Trader : public IObserver, public std::enable_shared_from_this<Trader> {
private:
std::weak_ptr<ISubject> subject_;
public:
Trader(std::shared_ptr<ISubject> subject) : subject_(subject) {
if (auto s = subject_.lock()) {
s->Attach(shared_from_this());
}
}
};
5.2 通知过程中的异常处理
观察者的Update方法可能抛出异常,需要妥善处理:
cpp复制void Notify() {
auto observers_copy = GetObserversCopy();
for (auto& weak_observer : observers_copy) {
if (auto observer = weak_observer.lock()) {
try {
observer->Update(event);
} catch (const std::exception& e) {
std::cerr << "Observer update failed: " << e.what() << std::endl;
// 可以选择移除故障观察者
Detach(observer);
}
}
}
}
5.3 性能瓶颈分析
观察者模式可能成为性能瓶颈的几个场景:
-
大量观察者:当观察者数量很多时,遍历通知会消耗大量时间
- 解决方案:分组通知、异步通知、优先级队列
-
高频更新:被观察者状态变化非常频繁
- 解决方案:节流(throttling)、去抖(debouncing)、批量更新
-
复杂更新逻辑:观察者的Update方法执行时间过长
- 解决方案:异步执行、工作队列
5.4 与Qt信号槽的比较
Qt框架提供了信号槽机制,本质上也是一种观察者模式:
cpp复制// Qt风格的观察者模式
class StockPrice : public QObject {
Q_OBJECT
signals:
void priceChanged(const QString& symbol, double price);
};
class KLineChart : public QObject {
Q_OBJECT
public slots:
void onPriceChanged(const QString& symbol, double price) {
// 更新K线图
}
};
// 连接信号槽
StockPrice apple;
KLineChart chart;
QObject::connect(&apple, &StockPrice::priceChanged,
&chart, &KLineChart::onPriceChanged);
与标准观察者模式相比,Qt信号槽的优势:
- 线程安全的事件队列
- 自动连接管理
- 更简洁的语法
劣势:
- 需要继承QObject
- 有一定的性能开销
- 与Qt框架强耦合
6. 现代C++中的观察者模式变体
6.1 使用std::function作为观察者
C++11以后,我们可以使用std::function实现更灵活的观察者模式:
cpp复制class Subject {
private:
std::vector<std::function<void(const Event&)>> observers_;
public:
template<typename F>
void Attach(F&& observer) {
observers_.emplace_back(std::forward<F>(observer));
}
void Notify(const Event& event) {
for (auto& observer : observers_) {
observer(event);
}
}
};
// 使用lambda作为观察者
Subject subject;
subject.Attach([](const Event& e) {
std::cout << "Event received: " << e.description << std::endl;
});
6.2 基于事件的观察者模式
我们可以实现一个更通用的事件系统:
cpp复制class EventDispatcher {
private:
using Handler = std::function<void(const Event&)>;
std::unordered_map<EventType, std::vector<Handler>> handlers_;
public:
void Subscribe(EventType type, Handler handler) {
handlers_[type].push_back(std::move(handler));
}
void Publish(const Event& event) {
auto it = handlers_.find(event.type);
if (it != handlers_.end()) {
for (auto& handler : it->second) {
handler(event);
}
}
}
};
// 使用示例
EventDispatcher dispatcher;
dispatcher.Subscribe(EventType::PRICE_UPDATE, [](const Event& e) {
// 处理价格更新
});
6.3 反应式编程风格
现代C++可以结合反应式编程思想实现观察者模式:
cpp复制template<typename T>
class Observable {
private:
std::vector<std::function<void(const T&)>> observers_;
public:
void Subscribe(std::function<void(const T&)> observer) {
observers_.push_back(std::move(observer));
}
void Next(const T& value) {
for (auto& observer : observers_) {
observer(value);
}
}
};
// 使用示例
Observable<double> priceStream;
priceStream.Subscribe([](double price) {
std::cout << "New price: " << price << std::endl;
});
priceStream.Next(150.5);
7. 测试与调试观察者模式
7.1 单元测试策略
观察者模式的测试要点:
- 测试观察者是否正确注册和注销
- 测试状态变化时是否触发通知
- 测试多个观察者时的通知顺序
- 测试异常情况下的行为
cpp复制TEST(ObserverPattern, BasicNotification) {
StockPrice stock("AAPL", 150.0);
MockObserver observer;
stock.Attach(&observer);
EXPECT_CALL(observer, Update(_)).Times(1);
stock.SetPrice(152.0);
}
TEST(ObserverPattern, DetachObserver) {
StockPrice stock("AAPL", 150.0);
MockObserver observer;
stock.Attach(&observer);
stock.Detach(&observer);
EXPECT_CALL(observer, Update(_)).Times(0);
stock.SetPrice(152.0);
}
7.2 内存泄漏检测
使用工具检测观察者模式中的内存泄漏:
cpp复制void TestMemoryLeak() {
auto stock = std::make_shared<StockPrice>("AAPL", 150.0);
{
auto observer = std::make_shared<MockObserver>();
stock->Attach(observer);
// observer离开作用域,应该自动从stock中移除
}
// 此时stock不应该持有任何观察者
ASSERT_EQ(stock->ObserverCount(), 0);
}
7.3 性能测试
测试观察者模式在不同场景下的性能:
cpp复制void BenchmarkNotification(benchmark::State& state) {
StockPrice stock("AAPL", 150.0);
std::vector<std::shared_ptr<MockObserver>> observers;
// 创建指定数量的观察者
for (int i = 0; i < state.range(0); ++i) {
auto observer = std::make_shared<MockObserver>();
stock.Attach(observer);
observers.push_back(observer);
}
// 测试通知性能
for (auto _ : state) {
stock.SetPrice(152.0);
}
}
BENCHMARK(BenchmarkNotification)->Arg(10)->Arg(100)->Arg(1000);
8. 实际项目中的最佳实践
8.1 观察者模式与SOLID原则
观察者模式很好地体现了SOLID原则:
- 单一职责原则:被观察者只负责维护状态和通知,观察者只负责响应更新
- 开闭原则:可以添加新观察者而不修改被观察者代码
- 里氏替换原则:观察者接口可以被各种具体观察者替换
- 接口隔离原则:观察者接口保持最小化
- 依赖倒置原则:高层模块不依赖低层模块,都依赖于抽象接口
8.2 设计决策点
在实际项目中实现观察者模式时,需要考虑以下设计决策:
-
同步 vs 异步通知:
- 同步:简单直接,但可能阻塞被观察者
- 异步:更复杂,但不会阻塞,适合耗时操作
-
推模型 vs 拉模型:
- 推模型:被观察者将变化数据推送给观察者
- 拉模型:观察者收到通知后主动从被观察者拉取数据
-
精确通知 vs 广播通知:
- 精确通知:只通知对特定变化感兴趣的观察者
- 广播通知:通知所有观察者,由观察者自行过滤
8.3 与其他模式的结合
观察者模式常与其他模式结合使用:
- 与中介者模式结合:通过中介者管理复杂的观察关系
- 与命令模式结合:将通知封装为命令对象
- 与组合模式结合:实现观察者树形结构
- 与状态模式结合:观察状态变化
8.4 在大型项目中的架构建议
对于大型项目,建议:
- 使用专门的事件总线或消息系统集中管理观察关系
- 为不同类型的事件定义清晰的接口和协议
- 实现观察者的优先级和过滤机制
- 提供完善的日志和监控,便于调试
- 考虑使用现有的消息库(如ZeroMQ、RabbitMQ等)实现分布式观察者模式
9. 性能优化与扩展
9.1 高效的事件匹配
当观察者数量很多时,高效的事件匹配变得重要:
cpp复制class EventSystem {
private:
using ObserverID = uint64_t;
std::unordered_map<EventType, std::unordered_map<ObserverID, Handler>> handlers_;
ObserverID nextID_ = 0;
public:
template<typename F>
ObserverID Subscribe(EventType type, F&& handler) {
ObserverID id = ++nextID_;
handlers_[type][id] = std::forward<F>(handler);
return id;
}
void Unsubscribe(EventType type, ObserverID id) {
if (auto it = handlers_.find(type); it != handlers_.end()) {
it->second.erase(id);
}
}
void Publish(const Event& event) {
if (auto it = handlers_.find(event.type); it != handlers_.end()) {
for (auto& [id, handler] : it->second) {
handler(event);
}
}
}
};
9.2 批量处理与节流
对于高频事件,实现批量处理和节流:
cpp复制class BatchedEventSystem {
private:
std::vector<Event> eventBatch_;
std::chrono::milliseconds batchInterval_;
std::thread batchThread_;
std::atomic<bool> running_{false};
public:
BatchedEventSystem(std::chrono::milliseconds interval)
: batchInterval_(interval) {
running_ = true;
batchThread_ = std::thread([this]() {
while (running_) {
std::this_thread::sleep_for(batchInterval_);
ProcessBatch();
}
});
}
~BatchedEventSystem() {
running_ = false;
if (batchThread_.joinable()) {
batchThread_.join();
}
}
void PostEvent(Event event) {
std::lock_guard<std::mutex> lock(mutex_);
eventBatch_.push_back(std::move(event));
}
private:
void ProcessBatch() {
std::vector<Event> batch;
{
std::lock_guard<std::mutex> lock(mutex_);
batch.swap(eventBatch_);
}
if (!batch.empty()) {
// 处理批量事件
BatchEvent batchEvent{std::move(batch)};
NotifyObservers(batchEvent);
}
}
};
9.3 分布式观察者模式
在分布式系统中实现观察者模式:
cpp复制class DistributedObserverProxy : public IObserver {
private:
rpc::Client& rpcClient_;
std::string remoteService_;
public:
DistributedObserverProxy(rpc::Client& client, const std::string& service)
: rpcClient_(client), remoteService_(service) {}
void Update(const Event& event) override {
rpcClient_.Call(remoteService_ + ".OnUpdate", event);
}
};
class DistributedSubject {
private:
std::vector<std::shared_ptr<IObserver>> localObservers_;
std::vector<rpc::ServiceStub> remoteObservers_;
public:
void AttachLocal(std::shared_ptr<IObserver> observer) {
localObservers_.push_back(observer);
}
void AttachRemote(const rpc::ServiceStub& stub) {
remoteObservers_.push_back(stub);
}
void Notify(const Event& event) {
// 通知本地观察者
for (auto& observer : localObservers_) {
observer->Update(event);
}
// 通知远程观察者
for (auto& stub : remoteObservers_) {
stub.Call("Update", event);
}
}
};
10. 观察者模式在C++项目中的实际应用
10.1 GUI框架中的事件处理
大多数GUI框架(如Qt、wxWidgets)都内置了观察者模式的实现:
cpp复制// 使用wxWidgets实现观察者模式
class MyFrame : public wxFrame {
public:
MyFrame() : wxFrame(nullptr, wxID_ANY, "Observer Example") {
button_ = new wxButton(this, wxID_ANY, "Click Me");
button_->Bind(wxEVT_BUTTON, &MyFrame::OnButtonClicked, this);
// 添加观察者
observers_.push_back([](const std::string& msg) {
std::cout << "Observer 1: " << msg << std::endl;
});
}
void AddObserver(std::function<void(const std::string&)> observer) {
observers_.push_back(observer);
}
private:
wxButton* button_;
std::vector<std::function<void(const std::string&)>> observers_;
void OnButtonClicked(wxCommandEvent& event) {
for (auto& observer : observers_) {
observer("Button was clicked!");
}
}
};
10.2 游戏开发中的观察者模式
在游戏开发中,观察者模式常用于处理游戏事件:
cpp复制// 游戏事件类型
enum class GameEventType { PLAYER_HIT, ENEMY_DESTROYED, LEVEL_COMPLETED };
struct GameEvent {
GameEventType type;
// 事件相关数据...
};
class GameEventSystem {
private:
std::unordered_map<GameEventType, std::vector<std::function<void(const GameEvent&)>>> handlers_;
public:
void Subscribe(GameEventType type, std::function<void(const GameEvent&)> handler) {
handlers_[type].push_back(handler);
}
void Publish(const GameEvent& event) {
if (auto it = handlers_.find(event.type); it != handlers_.end()) {
for (auto& handler : it->second) {
handler(event);
}
}
}
};
// 成就系统作为观察者
class AchievementSystem {
public:
AchievementSystem(GameEventSystem& events) {
events.Subscribe(GameEventType::ENEMY_DESTROYED, [this](const GameEvent& e) {
this->OnEnemyDestroyed(e);
});
}
private:
void OnEnemyDestroyed(const GameEvent& event) {
// 更新成就进度...
}
};
10.3 金融交易系统中的应用
在量化交易系统中,观察者模式用于处理市场数据:
cpp复制class TradingSystem {
private:
std::vector<std::shared_ptr<IStrategy>> strategies_;
public:
void AddStrategy(std::shared_ptr<IStrategy> strategy) {
strategies_.push_back(strategy);
}
void OnMarketData(const MarketData& data) {
for (auto& strategy : strategies_) {
strategy->ProcessMarketData(data);
}
}
void OnOrderUpdate(const OrderUpdate& update) {
for (auto& strategy : strategies_) {
strategy->ProcessOrderUpdate(update);
}
}
};
class MeanReversionStrategy : public IStrategy {
public:
void ProcessMarketData(const MarketData& data) override {
// 实现均值回归策略逻辑
}
void ProcessOrderUpdate(const OrderUpdate& update) override {
// 处理订单更新
}
};
11. 观察者模式的替代方案
虽然观察者模式非常有用,但在某些场景下,其他模式可能更合适:
11.1 回调函数
对于简单的通知需求,回调函数可能更轻量:
cpp复制class Button {
private:
std::function<void()> onClick_;
public:
void SetOnClick(std::function<void()> callback) {
onClick_ = std::move(callback);
}
void Click() {
if (onClick_) {
onClick_();
}
}
};
11.2 信号槽系统
如Qt的信号槽机制提供了更强大的功能:
cpp复制class StockMarket : public QObject {
Q_OBJECT
signals:
void priceUpdated(const QString& symbol, double price);
};
class PortfolioManager : public QObject {
Q_OBJECT
public slots:
void onPriceUpdated(const QString& symbol, double price) {
// 更新投资组合
}
};
11.3 事件总线
对于复杂的系统,事件总线提供了更松散的耦合:
cpp复制class EventBus {
private:
std::unordered_map<std::type_index, std::vector<std::function<void(const void*)>>> handlers_;
public:
template<typename Event>
void Subscribe(std::function<void(const Event&)> handler) {
auto& handlers = handlers_[typeid(Event)];
handlers.push_back([handler](const void* event) {
handler(*static_cast<const Event*>(event));
});
}
template<typename Event>
void Publish(const Event& event) {
auto it = handlers_.find(typeid(Event));
if (it != handlers_.end()) {
for (auto& handler : it->second) {
handler(&event);
}
}
}
};
12. C++20/23中的新特性应用
12.1 使用协程实现异步观察者
C++20引入的协程可以简化异步观察者实现:
cpp复制#include <coroutine>
struct EventAwaiter {
EventType type;
EventBus& bus;
std::optional<Event> result;
bool await_ready() const { return false; }
void await_suspend(std::coroutine_handle<> h) {
bus.Subscribe(type, [this, h](const Event& e) {
result = e;
h.resume();
});
}
Event await_resume() { return *result; }
};
EventAwaiter WaitForEvent(EventBus& bus, EventType type) {
return {type, bus};
}
Task<void> ProcessEvents() {
while (true) {
Event event = co_await WaitForEvent(bus, EventType::PRICE_UPDATE);
// 处理事件...
}
}
12.2 使用概念约束观察者接口
C++20概念可以更好地约束观察者接口:
cpp复制template<typename T>
concept Observer = requires(T o, const Event& e) {
{ o.Update(e) } -> std::same_as<void>;
};
template<Observer O>
class Subject {
private:
std::vector<O*> observers_;
public:
void Attach(O* observer) {
observers_.push_back(observer);
}
void Notify(const Event& event) {
for (auto observer : observers_) {
observer->Update(event);
}
}
};
12.3 使用span优化通知性能
C++20的span可以优化批量通知:
cpp复制void Notify(std::span<const Event> events) {
for (auto& observer : observers_) {
for (auto& event : events) {
observer->Update(event);
}
}
}
13. 跨平台与嵌入式环境考虑
13.1 内存受限环境
在嵌入式系统中,需要考虑:
- 避免动态内存分配
- 使用固定大小的观察者容器
- 简化事件数据结构
cpp复制template<typename Observer, size_t MaxObservers>
class StaticSubject {
private:
std::array<Observer*, MaxObservers> observers_{};
size_t count_ = 0;
public:
bool Attach(Observer* observer) {
if (count_ < MaxObservers) {
observers_[count_++] = observer;
return true;
}
return false;
}
void Notify(const Event& event) {
for (size_t i = 0; i < count_; ++i) {
observers_[i]->Update(event);
}
}
};
13.2 跨平台事件处理
对于跨平台代码,需要抽象平台特定细节:
cpp复制class PlatformEvent {
// 平台无关的事件表示
};
class PlatformEventAdapter {
public:
virtual ~PlatformEventAdapter() = default;
virtual PlatformEvent ConvertFromNative(const NativeEvent&) = 0;
virtual NativeEvent ConvertToNative(const PlatformEvent&) = 0;
};
class CrossPlatformSubject {
private:
std::unique_ptr<PlatformEventAdapter> adapter_;
std::vector<std::function<void(const PlatformEvent&)>> observers_;
public:
void SetAdapter(std::unique_ptr<PlatformEventAdapter> adapter) {
adapter_ = std::move(adapter);
}
void HandleNativeEvent(const NativeEvent& event) {
if (adapter_) {
auto platformEvent = adapter_->ConvertFromNative(event);
Notify(platformEvent);
}
}
void Notify(const PlatformEvent& event) {
for (auto& observer : observers_) {
observer(event);
}
}
};
14. 性能关键系统的优化技巧
14.1 缓存友好的观察者模式
优化内存访问模式:
cpp复制class CacheFriendlySubject {
private:
struct ObserverData {
Observer* observer;
uint32_t notificationMask; // 位掩码表示感兴趣的事件类型
};
std::vector<ObserverData> observers_;
public:
void Attach(Observer* observer, uint32_t eventMask) {
observers_.push_back({observer, eventMask});
}
void Notify(uint32_t eventType, const Event& event) {
for (auto& [observer, mask] : observers_) {
if (mask & eventType) {
observer->Update(event);
}
}
}
};
14.2 无锁观察者列表
使用原子操作实现无锁观察者列表:
cpp复制class LockFreeSubject {
private:
struct Node {
Observer* observer;
std::atomic<Node*> next;
};
std::atomic<Node*> head_{nullptr};
public:
void Attach(Observer* observer) {
Node* newNode = new Node{observer, nullptr};
newNode->next = head_.load(std::memory_order_relaxed);
while (!head_.compare_exchange_weak(
newNode->next, newNode,
std::memory_order_release,
std::memory_order_relaxed)) {}
}
void Notify(const Event& event) {
Node*
