一. 什么是观察者设计模式?
信号与槽的底层实现机制就是观察者设计模式。观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主体是通知的发布者,它发出通知时,并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用。
观察者模式完美的将观察者和被观察的对象分离开,观察者模式在模块之间划定了清晰的接线,提高了应用程序的可维护性和重用性。
二. 观察者设计模式的编程套路是什么?
1.设定两者类,一个为观察者类,一个为被观察者类。
2.观察者类中,定义一个对某个事件感兴趣的处理函数,一般也叫槽函数。
3.被观察者类中,定义一个数据结构,用来保存观察者对哪一个事件id感兴起,使用map建立对应关应
4.被观察者类中,定义两个方法函数:
一个方法为:添加观察者与其感兴趣的事件id加入到容器之中。
另一个方法为:通知事件函数执行逻辑:首先遍历容器之中,有没有感兴趣的事件ID,如果有,则代表一系列的观察者,对这个事件感兴趣,那么再次遍历观察者列表,让每一个观察者执行相应的槽函数。
三. 代码
#include <iostream>
#include <vector>
using namespace std;
template <class TParam>
class SlotBase
{
public:
virtual void slotFunction(TParam param) = 0;
virtual ~SlotBase() = default;
};
template <class TRecver,class TParam>
class Slot : public SlotBase<TParam>
{
private:
TRecver* m_pRecver;//定义一个接收者的指针,在构造中对其初始化
void (TRecver::*m_func)(TParam param);//定义一个接收者类中的成员函数指针
public:
Slot(TRecver* pObj, void(TRecver::*func)(TParam))
{
this->m_pRecver = pObj;
this->m_func = func;//使用类外的接收者类的对象指计与接收者类中的成员函数指针进行始化
}
void slotFunction(TParam param)override
{
(m_pRecver->*m_func)(param);//成员对象指针调用类里的成员函数
}
};
//定义一个信号类
template <class TParam>
class Signal
{
private:
vector<SlotBase<TParam>*> signal_vector;
public:
template<class TRecver>
void addSlot(TRecver* pObj, void (TRecver::*func)(TParam))
{
signal_vector.push_back(new Slot<TRecver,TParam>(pObj,func));
}
void operator()(TParam param)
{
for(SlotBase<TParam>*p : signal_vector)
{
p->slotFunction(param);
}
}
};
class Recver1
{
public:
void func1(int param)
{
cout << "这是Recver1中给定方法,参数为:"<<param<<endl;
}
};
class Recver2
{
public:
void func2(int param)
{
cout << "这是Recver2中给定方法,参数为:"<<param<<endl;
}
};
class SendObj
{
public:
Signal<int> valueChanged;
public:
void testSignal(int value)
{
valueChanged(value);
}
};
#define connect(sender,signal,recver,method) (sender)->signal.addSlot(recver,method);
int main()
{
Recver1* r1 = new Recver1;
Recver2* r2 = new Recver2;
SendObj* sd = new SendObj;
connect(sd,valueChanged,r1,&Recver1::func1);
connect(sd,valueChanged,r2,&Recver2::func2);
sd->testSignal(10000);
return 0;
}