概念
Observer
模式也称为
发布-订阅(publish-subscribe),目标就是通知的发布者,观察者 则是通知的订阅者(接受通知),常用于解耦事件的观察和事件最终的处理方式
Observer
模式要解决的问题为:建立一个 一(Subject
)对多(
Observer
)的依赖关系,并且做到当“一”变化的时候,依赖这个“一” 的多也能够同步改变。
例子:对同一组数据进行统计分析时候,我们希望 能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。 这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够 同时改变。
UML类视图
角色
Subject类:它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject类:具体主题,将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
Observer类:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;。
ConcreteObserver类:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调
代码实现
//抽象类观察者
class Observer
{
public:
//观察者行为接口
virtual void handler(int msgid) = 0;
};
//具体观察者1
class Observer1 : public Observer
{
public:
//观察者具体的行为
void handler(int msgid)
{
switch (msgid)
{
case 2:
cout << "Observer1 recv 2 msgid" << endl;
break;
case 3:
cout << "Observer1 recv 3 msgid" << endl;
break;
}
}
};
class Observer2 : public Observer
{
public:
void handler(int msgid)
{
switch (msgid)
{
case 1:
cout << "Observer2 recv 1 msgid" << endl;
break;
case 3:
cout << "Observer2 recv 3 msgid" << endl;
break;
}
}
};
class Observer3 : public Observer
{
public:
void handler(int msgid)
{
switch (msgid)
{
case 1:
cout << "Observer3 recv 1 msgid" << endl;
break;
case 2:
cout << "Observer3 recv 2 msgid" << endl;
break;
}
}
};
//主题类,
class Subject
{
public:
// 给主题增加观察者对象及对象所感兴趣的事件
void addObserver(Observer *ob, int msgid)
{
_subMap[msgid].push_back(ob);
}
// 主题检测发生改变,通知相应的观察者对象处理事件
void dispatch(int msgid)
{
auto it = _subMap.find(msgid);
if (it != _subMap.end())
{
for (Observer *p : it->second)
{
p->handler(msgid);
}
}
}
private:
//存储每个观察者感兴趣的msgid事件
unordered_map<int, list<Observer *>> _subMap;
};
int main()
{
Subject sub;
Observer *ob1 = new Observer1();
Observer *ob2 = new Observer2();
Observer *ob3 = new Observer3();
sub.addObserver(ob1, 2);
sub.addObserver(ob1, 3);
sub.addObserver(ob2, 1);
sub.addObserver(ob2, 3);
sub.addObserver(ob3, 1);
sub.addObserver(ob3, 2);
int msgid;
while (1)
{
//主题类轮询监听接收过来的msgid,然后去发布给观察者
cout << "请输入msgid:";
cin >> msgid;
if (msgid == -1)
break;
sub.dispatch(msgid);
}
}
再比如:我们经常使用微信,每天都能收到各种自己关注的公众号推送来的消息文章。这就是一个典型的发布订阅。我们关注了某个公众号,就相当于给公众号粉丝列表添加了一个用户,当公众号推送消息时,发布的消息推送给所有的粉丝,粉丝就可以收到这些消息