观察者模式:
应用于发布-订阅消息模型中,订阅者订阅一个主题后,当有新消息到达时,所有订阅者都会收到通知。
主要关注的是对象之间的通信。是一种对象之间的一对多关系,多个对象依赖于一个对象,当被依赖的那个对象的状态发生改变时,其他对象都能够接收到相应的通知。
举个例子:
就像我们去看报纸,不用去挨个挨家出版社去问报纸做好了没,而是打个电话向出版社订阅报纸,等到哪个出版社的报纸好了,就会通知你。
简单画个图方便理解:
当我的Observer这些订阅者去订阅同一个主题Subject时,也就是多个对象依赖同一个对象,当主题检测有消息发生后会通知我们的订阅者。
这里也有具体的实现代码如下:
#include<iostream>
#include<unordered_map>
#include<list>
using namespace std;class Observer {//观察者抽象类
public://处理消息的接口virtual void handler(int msgid) = 0;
};
class Observer1 :public Observer {
public:void handler(int msgid) {switch (msgid) {case 1:cout << "Observer1 recv 1 msg!" << endl;break;case 2:cout << "Observer1 recv 2 msg!" << endl;break;default:cout << "Observer1 recv unkown msg!" << endl;break;}}
};
class Observer2 :public Observer {
public:void handler(int msgid) {switch (msgid) {case 2:cout << "Observer2 recv 2 msg!" << endl;break;default:cout << "Observer2 recv unkown msg!" << endl;break;}}
};
class Observer3 :public Observer {
public:void handler(int msgid) {switch (msgid) {case 1:cout << "Observer3 recv 1 msg!" << endl;break;case 3:cout << "Observer3 recv 3 msg!" << endl;break;default:cout << "Observer3 recv unkown msg!" << endl;break;}}
};
//主题类
class Subject {
public://给主题增加观察者对象void addObserver(Observer* o ,int msgid) {_subMap[msgid].push_back(o);}//主题检测发生改变,通知相应的观察者对象void dispatch(int msgid) {auto it = _subMap.find(msgid);if (it != _subMap.end()) {for (Observer* p : it->second) {p->handler(msgid);}}}
private:unordered_map<int, list<Observer*>> _subMap;
};
int main() {Subject sub;Observer* p1 = new Observer1();Observer* p2 = new Observer2();Observer* p3 = new Observer3();//订阅主题:每个观察者自己感兴趣的消息idsub.addObserver(p1, 1);sub.addObserver(p1, 2);sub.addObserver(p2, 2);sub.addObserver(p3, 1);sub.addObserver(p3, 3);int msgid = 0;for (;;) {cout << "输入消息id:"; cin >> msgid;if (msgid == -1) break;sub.dispatch(msgid);}return 0;
}
最后的运行截图如下:
可以看到当有消息id为1发生时,主题会检测到消息发生,然后通知给我们的观察者去处理消息。
Redis作为跨服务器通信的消息队列
知道Redis缓存数据库的童鞋应该知道,作为一个key-value格式来缓存热点数据之外,还有一个功能就是作为消息队列,也就是一个观察者设计模式的形式。
每一个观察者都会订阅一个通道,如果通道上有对应的消息事件发生,就会通知感兴趣的观察者。