C++观察者模式的实现
什么是观察者模式
1.观察者模式是一种对象行为模式。它定义对象间的一种一对多的以来关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并被自动更新。
2.在观察者模式中,主体是通知的发布者,他发出通知时并不需要知道谁是他的观察者,可以有任意数目的观察者订阅并接收通知。
3.观察者模式(Observer)完美的将观察者和被观察的对象分离开。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
4.观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用。
观察者模式设计思路
1.设定两个类,一个为观察者类,一个为被观察者类。
2.观察者类中,定义一个对某个事件感兴趣的处理函数,一般也叫槽函数。
3.被观察者类中,定义一个数据结构,用来保存观察者对哪一个事件id(信号)感兴趣,使用数据结构建立信号与对象之间的映射关系。
4.被观察者类中,定义两个方法函数:
4.1一个方法为:添加观察者与其感兴趣的事件id(信号)加入到容器之中。
4.2另一个方法为:信号函数。通知事件函数执行逻辑:首先遍历容器之中,有没有感兴趣的事件id,如果有,则代表一系列的观察者对这个事件感兴趣,那么再次遍历观察者列表,让每一个观察者执行相应的槽函数。
代码演示
定义信号接收者(观察者)类:
#include <iostream>
#include <map>
#include <list>
using namespace std;
//定义一个接收者的基类
class RecvBase
{
public:
virtual void slots_function(int msgid) = 0;
virtual ~RecvBase() = default;
};
//定义一个接收者的子类
class Recv : public RecvBase
{
private:
string name;
public:
Recv(string name) : name(name)
{ }
//实现槽函数:
void slots_function(int msgid) override
{
cout << "我是" << name;
switch(msgid){
case 1:
cout << "收到信号1" << endl;
break;
case 2:
cout << "收到信号2" << endl;
break;
case 3:
cout << "收到信号3" << endl;
break;
}
}
};
定义信号发出者(被观察者)类:
map,list为STL标准库中容器。
//定义一个信号的发出者
class Sender
{
private:
//定义一个Map容器来保存信号id与所有对此id感兴趣的接收者
// (id, (recv1,recv2,...))
map <int, list<RecvBase*>> senderMap;
public:
//把所有对某信号id感兴趣的接收者的对象加入到list容器之中
void addRecvFunction(int msgid, RecvBase* recv)
{
senderMap[msgid].push_back(recv);
}
//发出信号,并遍历所有感兴趣的接收者指针,让其执行相关的槽函数
void signal(int msgid)
{
auto it = senderMap.find(msgid);
for(RecvBase* p : it->second)
{
p->slots_function(msgid);
}
}
};
主函数验证:
int main()
{
//定义信号的发出者:
Sender sender;
//定义接收者对象:
RecvBase* recv1 = new Recv("zhangsan");
RecvBase* recv2 = new Recv("lisi");
RecvBase* recv3 = new Recv("wangwu");
//接收者与信号id绑定
sender.addRecvFunction(1, recv1); //将接收者1放入id=1的列表中
sender.addRecvFunction(2, recv2); //将接收者2放入id=2的列表中
sender.addRecvFunction(3, recv1); //将接收者1放入id=3的列表中
sender.addRecvFunction(3, recv2); //将接收者2放入id=3的列表中
sender.addRecvFunction(3, recv3); //将接收者3放入id=3的列表中
//从终端循环输入信号:
int msgid;
for(;;)
{
cin >> msgid; //cin为终端输入
if(msgid == -1)
{
break;
}
sender.signal(msgid); //发出信号
}
return 0;
}
运行结果:
因篇幅问题不能全部显示,请点此查看更多更全内容