观察者模式
观察者模式其实是最常见的设计模式,在工程中很常见;
C++中,同一线程中的不同类之间的消息总需要传递,传递方式就是注册一个回调函数(其实就是个类),当数据更新后,触发回调函数(注册类中的函数)。
//被观察者(需要把数据传出去):
class object
{
void register(observer* person)
{
memeber.insert({1,person});
}
void notifyObserver()
{
for(auto it:member)
{
it.second->onListern();
}
}
private:
map<int,observer> member;
}
//观察者
class observer
{
onListern()
{
cout<<"deal data"
}
}
可以看出来观察者模式很好用,数据传递到onListerner(),但是现在有个需求就是需要onlisterner()带有参数输入,那就要多写几个重载函数。
class observer
{
onListern(int type,void* data)
{
cout<<"deal data1"
}
onListern(int type,void* data,int len)
{
cout<<"deal data2"
}
}
-
需求变更
现在又一个新需求,就是新增了10个观察者,需要创建一个Observer基类,那就要再写10个类继承基类。
-
需求再次增加
然后又有新需求,观察者的数据需要传出去,也成为被观察者;
-
需求太多之后,类的数量成倍增加,还难以追踪
综上,传统的观察者模式还是有着参数不可变以及继承关系爆炸的问题,这两个问题目前看影响不大,但是放在工程中,如果不是代码本人阅读,通知链过长过于宽,就很难记得住代码流程。
所以结合C++11 新特性,其实观察者模式完全可以被函数指针(std::function)来代替,listen函数的参数可以使用可变参数语法来设计
先写一个简单的,只是使用std::function绑定观察者中的listen函数
class newobserver
{
onlistern(int type,void* data)
{
cout<<"new observer"
}
}
class newobject
{
void register(std::function<void(int,int)> fun)
{
static key++;
m_member.emplace(key,fun);
}
void notify(int a ,int b)
{
for(auto it:m_member)
{
it.second(a,b);
}
}
map<int ,std::function<void(int,int)> >m_member;
}
main.cpp
int main()
{
newobserver *myobserver = new newobserver;
auto fun = std::bind(&newobsever::onlistern,myobserver,std::placeholders::1,placeholders::2)
newobject *myobject = new newobject;
myobject->register(fun);
myobject->notify(333,444);
}
-
利用类模板
再写个复杂点的,上可变参数,C++11直接可以使用可变参数模板的语法,在此之前先上模板练练手,std:function<void(int,int)> 改用模板
template <typename FuncObserver>
class newObject
{
void register(FuncObserver fun)
{
m_memeber.emplace(key,fun)
}
void notify(int a)
{
for(auto it:m_member)
{
it.second(a);
}
}
}
main
{
newObject myobject;
newObsever myobsever;
std::fucntion<void(int)> fun = bind(&newobsever::onlister,&myobsever,::1,::2)
myobject.register(fun);
myobject.notify(33333);
}
-
更换为可变参数模板,其实这个在工程中不适用,容易带来未知的问题,不如先TO DO吧
-
又来一个需求
原来的object的类不能变,但是需求注册另外一类观察者dog,而dog本身是动物不是人,应该继承于animal类,不是一种I Observer类,没办法,强行使用双重继承,才能调用原本的object::register函数,这种是在工程中非常常见的需求,增加监听者,如果换乘上述的使用类函数,就可以避免双重继承。
class dog :public IObserver public IAnimal
{
}
class object
{
void register(observer* person)
{
}
}