1. 应用背景
观察者模式模式又称为发布-订阅模式。订阅消息的一方称为观察者,而发布消息的一般称为主题类。观察者在一开始的时候会向主题类注册自己感兴趣的事件,当主题类发布了一个特定事件的时候,观察者就会收到主题类的通知,从而完成状态变化。
在实际应用上,比如主题类是一组数据,由这组数据可以绘制出饼图、折线图、柱状图等统计图形。那么观察者就可以分别是以上三种图形。当数据发生变化的时候,统计图形也需要发生相应的变化。
2. 实现过程
在下面的例子中,我们首先先设计了一个观察者基类:ObserverBase
。这个类是作为抽象类规范接口用的,所有的观察者有统一的接口,方便主题类调用。
其次,不同的观察者从ObserverBase
进行继承,然后重写接口,完成某个消息到达时自己业务的封装。
而对于主题类而言,最主要的是提供两个接口:一个用于给观察者注册观察特定信号:addObserver,一个用于新的信号发生时通知观察者:dispatch
。对于注册,我们使用了哈希表+链表的数据结构来维护观察者的信息。对同一个事件感兴趣的观察者被链接在同一个list上,发生事件时依次进行通知。
以下是具体实现:
#include <iostream>
#include <unordered_map>
#include <list>
using namespace std;
class ObserverBase {
public:
virtual void handleMessage() = 0;
};
class Observer1 : public ObserverBase {
public:
void handleMessage() {
cout << "Handle Message 1!" << endl;
}
};
class Observer2 : public ObserverBase {
public:
void handleMessage() {
cout << "Handle Message 2!" << endl;
}
};
class Subject {
public:
void addObserver(ObserverBase* obj, int messageId) {
subList_[messageId].push_back(obj);
}
// 主题发生变化,通知观察者
void dispatch(int newMsg) {
auto it = subList_.find(newMsg);
if (it != subList_.end()) {
for (auto curObj : subList_[newMsg]) {
curObj->handleMessage();
}
}
}
private:
unordered_map<int, list<ObserverBase*>> subList_;
};
int main() {
// 主题类
Subject* sub = new Subject();
// 观察者
Observer1* obj1 = new Observer1();
Observer2* obj2 = new Observer2();
// 观察者1对信号1感兴趣
sub->addObserver(obj1, 1);
// 观察者2对信号2感兴趣
sub->addObserver(obj2, 2);
// 新信号来了
sub->dispatch(1);
sub->dispatch(2);
sub->dispatch(1);
return 0;
}
运行结果: