事件总线是一种解耦发布者与订阅者的通信机制,通过维护事件类型到订阅者列表的映射实现事件分发。1. 使用typeid获取事件类型并分发事件;2. 事件内存由事件总线在publish后释放;3. 避免性能瓶颈可采用异步处理、事件过滤、分层事件总线、线程池等策略;4. 处理异常可通过try-catch块、错误处理函数或返回值机制;5. 保证事件顺序可通过单线程处理、序列化到消息队列或使用版本号控制。

事件总线/发布订阅模式,简单来说,就是让不同的对象(发布者和订阅者)在不知道彼此的情况下进行通信。发布者发出事件,订阅者接收并处理感兴趣的事件。这是一种解耦的好方法,能让系统更灵活、可扩展。

解决方案

C++中实现事件总线,主要思路是维护一个事件类型到订阅者列表的映射。当某个事件发生时,事件总线负责通知所有订阅了该事件的订阅者。以下是一种基础实现方式,可以根据具体需求进行扩展:
立即学习“C++免费学习笔记(深入)”;
#include <iostream>
#include <vector>
#include <map>
#include <functional>
#include <memory>
// 定义事件基类
class Event {
public:
virtual ~Event() = default;
};
// 定义事件处理函数的类型别名
using EventHandler = std::function<void(Event*)>;
// 事件总线类
class EventBus {
public:
// 订阅事件
void subscribe(const std::string& eventType, EventHandler handler) {
subscribers_[eventType].push_back(handler);
}
// 取消订阅事件
void unsubscribe(const std::string& eventType, EventHandler handler) {
auto& subs = subscribers_[eventType];
subs.erase(std::remove_if(subs.begin(), subs.end(),
[&](const EventHandler& h) { return h.target<void(Event*)>() == handler.target<void(Event*)>(); }),
subs.end());
}
// 发布事件
void publish(Event* event) {
const std::string eventType = typeid(*event).name(); // 获取事件类型名称
auto it = subscribers_.find(eventType);
if (it != subscribers_.end()) {
for (const auto& handler : it->second) {
handler(event);
}
}
delete event; // 重要:事件由发布者创建,总线负责传递,最后由总线释放内存
}
private:
std::map<std::string, std::vector<EventHandler>> subscribers_;
};
// 示例事件类
class ButtonClickEvent : public Event {
public:
ButtonClickEvent(int buttonId) : buttonId_(buttonId) {}
int buttonId() const { return buttonId_; }
private:
int buttonId_;
};
// 示例订阅者类
class Logger {
public:
void onButtonClick(Event* event) {
ButtonClickEvent* clickEvent = dynamic_cast<ButtonClickEvent*>(event);
if (clickEvent) {
std::cout << "Button " << clickEvent->buttonId() << " clicked!" << std::endl;
}
}
};
int main() {
EventBus bus;
Logger logger;
// 订阅事件
bus.subscribe(typeid(ButtonClickEvent).name(), std::bind(&Logger::onButtonClick, &logger, std::placeholders::_1));
// 发布事件
bus.publish(new ButtonClickEvent(1));
bus.publish(new ButtonClickEvent(2));
return 0;
}这个例子展示了如何定义事件、订阅事件、发布事件。关键点在于使用typeid来获取事件的类型信息,这使得我们可以根据事件类型来分发事件。 注意,事件的内存管理是个需要考虑的问题,这里选择在publish函数中释放事件内存。

事件总线在大型系统中可能会成为性能瓶颈。想象一下,如果一个事件被成千上万的订阅者订阅,每次发布事件都需要通知所有订阅者,这会消耗大量的CPU和网络资源。可以考虑以下优化策略:
事件处理函数可能会抛出异常。如果事件总线直接调用事件处理函数,那么异常可能会导致程序崩溃。因此,需要一种机制来处理事件处理中的异常。
选择哪种方法取决于具体的需求。 使用try-catch块是最简单的方法,但它可能会隐藏一些错误。 使用错误处理函数可以提供更灵活的错误处理机制。 使用返回值可以提供更明确的错误信息。
在某些场景下,事件的顺序非常重要。例如,如果一个事件表示账户余额增加,另一个事件表示账户余额减少,那么这两个事件的顺序必须得到保证。否则,可能会导致账户余额错误。
选择哪种方法取决于具体的需求。 单线程处理是最简单的方法,但它可能会成为性能瓶颈。 序列化可以保证事件的顺序,但它会增加系统的复杂性。 版本号可以提供更灵活的顺序保证机制。
以上就是C++中如何设计事件总线_发布订阅模式的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号