设计模式—观察者模式(发布-订阅模式)
一、简介
发布-订阅模式是一种消息传递模式,用于实现对象间的一对多依赖关系。在这种模式中:
- 发布者(Publisher)不直接向订阅者(Subscriber)发送消息
- 发布者和订阅者通过一个中介(通常称为事件总线或消息代理)进行通信
- 订阅者可以订阅感兴趣的事件,发布者可以发布事件
这种模式实现了发布者和订阅者的解耦,提高了系统的灵活性和可扩展性。
二、原理
2.1核心组件:
Publisher(发布者):产生事件/消息的对象
Subscriber(订阅者):接收并处理事件的对象
Event Bus/Message Broker(事件总线):管理订阅关系,负责将消息从发布者路由到订阅者
2.2工作流程:
订阅者向事件总线注册对特定事件的兴趣
发布者向事件总线发布事件
事件总线将事件传递给所有注册的订阅者
三、C++实现
以下是发布-订阅模式的简单C++实现:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <memory>
// 前置声明
class EventBus;
// 订阅者接口
class Subscriber {
public:
virtual ~Subscriber() = default;
virtual void handleEvent(const std::string& event, const std::string& message) = 0;
};
// 具体订阅者
class ConcreteSubscriber : public Subscriber {
public:
ConcreteSubscriber(const std::string& name) : name_(name) {}
void handleEvent(const std::string& event, const std::string& message) override {
std::cout << name_ << " received event '" << event
<< "' with message: " << message << std::endl;
}
private:
std::string name_;
};
// 事件总线
class EventBus {
public:
// 订阅事件
void subscribe(const std::string& event, Subscriber* subscriber) {
subscribers_[event].push_back(subscriber);
}
// 取消订阅
void unsubscribe(const std::string& event, Subscriber* subscriber) {
auto& subs = subscribers_[event];
subs.erase(std::remove(subs.begin(), subs.end(), subscriber), subs.end());
}
// 发布事件
void publish(const std::string& event, const std::string& message) {
if (subscribers_.find(event) != subscribers_.end()) {
for (auto subscriber : subscribers_[event]) {
subscriber->handleEvent(event, message);
}
}
}
private:
std::map<std::string, std::vector<Subscriber*>> subscribers_;
};
// 发布者
class Publisher {
public:
Publisher(EventBus& eventBus) : eventBus_(eventBus) {}
void publish(const std::string& event, const std::string& message) {
eventBus_.publish(event, message);
}
private:
EventBus& eventBus_;
};
int main() {
EventBus eventBus;
// 创建订阅者
ConcreteSubscriber sub1("Subscriber1");
ConcreteSubscriber sub2("Subscriber2");
ConcreteSubscriber sub3("Subscriber3");
// 订阅事件
eventBus.subscribe("event1", &sub1);
eventBus.subscribe("event1", &sub2);
eventBus.subscribe("event2", &sub2);
eventBus.subscribe("event2", &sub3);
// 创建发布者
Publisher publisher(eventBus);
// 发布事件
publisher.publish("event1", "First event message");
publisher.publish("event2", "Second event message");
// 取消订阅
eventBus.unsubscribe("event1", &sub2);
// 再次发布
publisher.publish("event1", "Event after unsubscribe");
return 0;
}
代码运行结果:
四、应用场景
- GUI系统中的事件处理
- 分布式系统中的消息传递
- 微服务架构中的服务间通信
- 游戏开发中的事件系统
- 日志系统和监控系统
优点
- 松耦合:发布者和订阅者不需要知道对方的存在
- 可扩展性:可以轻松添加新的发布者或订阅者
- 灵活性:订阅者可以动态订阅或取消订阅事件
缺点
- 调试困难:由于间接性,事件流可能难以跟踪
- 性能开销:消息传递可能比直接调用慢
- 可能导致内存泄漏:如果订阅者没有正确取消订阅
发布-订阅模式是现代软件架构中非常重要的模式,特别是在需要组件间松散耦合的系统中。
参考文章: