設計模式—觀察者模式(發布-訂閱模式)
一、簡介
發布-訂閱模式是一種消息傳遞模式,用于實現對象間的一對多依賴關系。在這種模式中:
- 發布者(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系統中的事件處理
- 分布式系統中的消息傳遞
- 微服務架構中的服務間通信
- 游戲開發中的事件系統
- 日志系統和監控系統
優點
- 松耦合:發布者和訂閱者不需要知道對方的存在
- 可擴展性:可以輕松添加新的發布者或訂閱者
- 靈活性:訂閱者可以動態訂閱或取消訂閱事件
缺點
- 調試困難:由于間接性,事件流可能難以跟蹤
- 性能開銷:消息傳遞可能比直接調用慢
- 可能導致內存泄漏:如果訂閱者沒有正確取消訂閱
發布-訂閱模式是現代軟件架構中非常重要的模式,特別是在需要組件間松散耦合的系統中。
參考文章:
1.“牽一發而動全身”——我用觀察者模式簡單模擬吃雞
2.《推薦C++ 23種設計模式》系列第十九期:觀察者模式【架構設計與實現】