最近由于学cocos2d-x3.2,看到其中的回调函数使用了std::bind,发现这是一个挺有趣的东西,它可以绑定一个函数,甚至一个函数对象,生成一个绑定了函数参数的函数对象,所以尝试用它写了一下观察者模式。
首先是观察者单例:
Ref是模仿cocos2d-x写的一个包含最基础引用计数的基类。
.h文件
#include "Singleton.h"
#include "Ref.h"
#include "RefManage.h"
#include <functional>
/**
* 消息管理(单例,尝试实现类似cocos2d-x观察者模式)
*/
class Notification :public Singleton<Notification>
{
public:
//发出消息
void postMessage(const std::string& msg,Ref* data);
//添加观察者
void addObserver(Ref* target,std::function<void(Ref*)> fun,const std::string& msg);
//删除观察者
bool removeObserver(Ref* ref,const std::string& msg);
//消息派发
void dispatchMsg();
public:
struct ObserverStr
{
Ref* _ref; //观察者对象
std::function<void(Ref*)> _fun; //绑定的类成员函数
std::string _msg; //监听的消息
};
struct MsgStr
{
std::string _msg; //发出的消息
Ref* _data; //附带的数据
};
private:
Notification(void);
~Notification(void);
friend Singleton<Notification>;
friend std::auto_ptr<Notification>;
private:
std::vector<ObserverStr> m_observerVector; //观察者列表
std::vector<MsgStr> m_msgVector; //消息列表
};
.cpp
#include "Notification.h"
Notification::Notification(void)
{
m_observerVector.clear();
}
Notification::~Notification(void)
{
m_observerVector.clear();
}
void Notification::postMessage( const std::string& msg,Ref* data )
{
MsgStr msgstr = {msg,data};
m_msgVector.push_back(msgstr);
}
void Notification::addObserver( Ref* target,std::function<void(Ref*)> fun,const std::string& msg )
{
ObserverStr obstr = {target,fun,msg};
m_observerVector.push_back(obstr);
}
bool Notification::removeObserver( Ref* ref,const std::string& msg )
{
for (auto it = m_observerVector.begin();it!=m_observerVector.end();++it)
{
if ((*it)._ref == ref && (*it)._msg.compare(msg)==0)
{
m_observerVector.erase(it);
return true;
}
}
return false;
}
void Notification::dispatchMsg()
{
for (auto i = m_msgVector.begin();i!=m_msgVector.end();)
{
bool isErase = false;
for (auto j = m_observerVector.begin();j!=m_observerVector.end();++j)
{
if ((*i)._msg.compare((*j)._msg) == 0)
{
((*j)._fun)((*i)._data);<span style="white-space:pre"> </span>//这是调用绑定的成员函数
i = m_msgVector.erase(i);
isErase = true;
}
}
if(!isErase)
++i;
}
}
测试类AB:
class ChildA : public Ref
{
public:
ChildA(){}
~ChildA(){};
void postmsg(MyString* str){
Notification::getInstance()->postMessage("child",str);}
};
class ChildB :public Ref
{
public:
ChildB(){}
void printdata(Ref* data) {
MyString* str = (MyString*)data;
std::cout<<(str->m_str)<<std::endl;
}
};
//用于传递的Data,也要继承Ref
class MyString :public Ref
{
public:
MyString(const std::string& str)
{m_str = str;}
std::string m_str;
};
主函数测试:
ChildA* p = new ChildA;
ChildB* q = new ChildB;
//添加观察者
Notification::getInstance()->addObserver(q,std::bind(&ChildB::printdata,q,std::placeholders::_1),"child");
//发送消息
MyString* str = new MyString("data");
p->postmsg(str);
上面
addObserver时用了std::bind绑定ChildB的成员函数,这个函数接收一个参数,这里用的std::placeholders::_1是占位符,用来预留了参数的位置,_1指的是通过bind后的函数调用时第一个参数绑定到原函数的第一个参数位置。
最后消息循环中循环调用来派发消息:
Notification::getInstance()->dispatchMsg();
从而通过bind的函数调用实现通知的效果。
测试结束时应该remove观察者。
测试结果:
使用std::function和std::bind似乎可以实现许多耦合度较低的设计模式,这里只是尝试一下。
写得不好,欢迎指正。