使用std::function和std::bind写的观察者模式

最近由于学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似乎可以实现许多耦合度较低的设计模式,这里只是尝试一下。


写得不好,欢迎指正。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值