c++自定義消息管理機制(類似cocos2d-x的實現方式)

       某日寫邏輯的時候,突然想到,關於消息管理機制,於是想到cocos2dx的__NotificationCenter,雖然不是寫cocos2dx了,但是未嘗不可自己寫一套類似的消息管理機制,方便通知。

      因此直接借(chao)鑑(xi)它裏面的消息管理機制了:


1.Ref基類

      Ref基類的目的是讓我需要訂閱消息的對象的類繼承自他,這樣的話我的對象可以通過強轉到Ref類型來保存到Notification中,而對於消息中心來說也不用知道訂閱消息的對象究竟是哪個類型。

Ref.h:

class Ref
{
public:
	Ref();
	virtual ~Ref();
};

//把子類成員函數的指針當做參數傳到觀察者用以當做回調函數
//typedef void(Ref::*pdc)();
typedef void (Ref::*SEL_CallFunc)();
typedef void (Ref::*SEL_CallFuncO)(Ref* _ref);

#define CC_CALLFUNC_SELECTOR(_SELECTOR) static_cast<SEL_CallFunc>(&_SELECTOR)
#define CC_CALLFUNCO_SELECTOR(_SELECTOR) static_cast<SEL_CallFuncO>(&_SELECTOR)

#define callfunc_selector(_SELECTOR) CC_CALLFUNC_SELECTOR(_SELECTOR)
#define callfuncO_selector(_SELECTOR) CC_CALLFUNCO_SELECTOR(_SELECTOR)
關於宏定義:宏定義部分其實多次包裝,把某個訂閱消息的對象成員函數強轉成Ref型的函數指針,在發佈消息的時候通過該指針調用回調函數,我看cocos2dx中有寫好了,就直接拿過來了0.0
Ref.cpp:沒什麼東西就不貼了
到這裏,基類是定義好了,接下來實現觀察者對象,即存儲訂閱消息的對象,以及消息名字,函數指針等一系列的數據信息。


2.NotificationObserver觀察者對象

如下:

class NotificationObserver {
public:
	NotificationObserver(Ref*target, string name, SEL_CallFunc selector)
	{
		m_name = name;
		m_target = target;
		m_selector = selector;
	}
	NotificationObserver(Ref*target, string name, SEL_CallFuncO selector, Ref* _ref)
	{
		m_name = name;
		m_target = target;
		m_Oselector = selector;
	}
	~NotificationObserver(){}
	Ref*getTarget()
	{
		return m_target;
	}
	string GetName()
	{
		return m_name;
	}
	/*SEL_CallFunc getCallBack(){
		return m_selector;
	}*/
	void ObserverCallBack()
	{
		if (m_target)
		{
			(m_target->*m_selector)();
		}
	}
	void ObserverCallBack(Ref* ref)
	{
		if (m_target)
		{
			(m_target->*m_Oselector)(ref);
		}
	}
private:
	Ref*	m_target;
	string	m_name;
	SEL_CallFunc	m_selector ;
	SEL_CallFuncO	m_Oselector;
	//SEL_CallFuncI m_
};
因爲東西少,沒分cpp了,至於Ref,因爲我建文件的時候建立的是類,直接包含cpp,這個是放在NotificationCenter.h了,接下來實現消息派發中心,負責訂閱消息,派送消息等功能。


3.NotificationCenter消息管理中心

消息中心必須是單例,在一個程序中只能有一個存在。

NotificationCenter.h

#ifndef __NOTIFICATION_CENTER_
#define __NOTIFICATION_CENTER_

#pragma once
#include"Ref.h"
#include <iostream>
#include<vector>
#include <list>
#include<functional>
using namespace std;

class NotificationObserver;
class NotificationCenter:
{
public:
	NotificationCenter();
	~NotificationCenter();
	static NotificationCenter*getInstance();
	static void destroyInstance();
	//添加觀察者
	//被觀察的對象,被觀察的方法,名字標籤
	void addObserver(Ref*target,string name, SEL_CallFunc selector);
	void addObserver(Ref*target, string name, SEL_CallFuncO selector,Ref* _ref);
	//移除觀察者
	void removeObserver(Ref*target, string name);
	//清空觀察者
	int removeAllObservers(Ref *target);
	//判斷該觀察者是否已經添加過了
	bool ObserverExisted(Ref *target,string name);

	void PostNotification(string name);

	void PostNotification(string name ,Ref* psender);
private:
	vector<NotificationObserver*>m_array;

};

class NotificationObserver :
{
public:
	NotificationObserver(Ref*target, string name, SEL_CallFunc selector)
	{
		m_name = name;
		m_target = target;
		m_selector = selector;
	}
	NotificationObserver(Ref*target, string name, SEL_CallFuncO selector, Ref* _ref)
	{
		m_name = name;
		m_target = target;
		m_Oselector = selector;
	}
	~NotificationObserver(){}
	Ref*getTarget()
	{
		return m_target;
	}
	string GetName()
	{
		return m_name;
	}
	/*SEL_CallFunc getCallBack(){
		return m_selector;
	}*/
	void ObserverCallBack()
	{
		if (m_target)
		{
			(m_target->*m_selector)();
		}
	}
	void ObserverCallBack(Ref* ref)
	{
		if (m_target)
		{
			(m_target->*m_Oselector)(ref);
		}
	}
private:
	Ref*	m_target;
	string	m_name;
	SEL_CallFunc	m_selector ;
	SEL_CallFuncO	m_Oselector;
	//SEL_CallFuncI m_
};
#endif

NotificationCenter.cpp

</pre><pre name="code" class="cpp">#include "stdafx.h"

#include "NotificationCenter.h"


static NotificationCenter *_notification = nullptr;
NotificationCenter::NotificationCenter()
{
	m_array.clear();
}
NotificationCenter::~NotificationCenter()
{
}
NotificationCenter*NotificationCenter::getInstance()
{
	if (_notification != nullptr)
	{
		return _notification;
	}
	_notification = new NotificationCenter;
	return _notification;
}

void NotificationCenter::destroyInstance()
{
	if(_notification!=nullptr)
	delete _notification;
}

bool NotificationCenter::ObserverExisted(Ref *target, string name)
{
	NotificationObserver *obj = nullptr;
	for each (obj in m_array)
	{
		if (!obj)
		{
			continue;
		}
		
		if (obj->getTarget()==target && obj->GetName()==name)
		{
			return true;
		}
	}
	return false;
}
void NotificationCenter::addObserver(Ref*target, string name, SEL_CallFunc selector)
{
	
	if (this->ObserverExisted(target, name))
	{
		return;
	}
	NotificationObserver *observe = new NotificationObserver(target, name, selector);
	m_array.push_back(observe);
}
//帶參數的
void NotificationCenter::addObserver(Ref*target, string name, SEL_CallFuncO selector, Ref* _ref)
{

	if (this->ObserverExisted(target, name))
	{
		return;
	}
	Ref* ref = new Ref();
	NotificationObserver *observe = new NotificationObserver(target, name, selector,_ref);
	//std::function<void()> func = std::bind(&Ref::update, ref);
	//NotificationObserver *observe = new NotificationObserver(std::bind(&Ref::update, ref), name, selector);
	m_array.push_back(observe);
}
void NotificationCenter::removeObserver(Ref*target, string name)
{
	//vector<NotificationObserver*>::iterator itor;
	auto itor = m_array.begin();
	int i = 0;
	for (itor = m_array.begin(); itor != m_array.end();)
	{
		if ((*itor)->getTarget() == target && ((*itor)->GetName() == name))
		{
			//delete m_array.at(i);
			delete *itor;
			itor = m_array.erase(itor);
		}
		else{
			i++;
			itor++;
		}
	}
}
int NotificationCenter::removeAllObservers(Ref*target)
{
	vector<NotificationObserver*>::iterator itor;
	itor = m_array.begin();
	for (itor = m_array.begin(); itor != m_array.end();)
	{
		if (((NotificationObserver*)*itor)->getTarget()== target)
		{
			delete *itor;
			//delete m_array.at(i);
			itor=m_array.erase(itor);
		}
		else{
			itor++;
		}
	}
	return 0;
}


void NotificationCenter::PostNotification(string name, Ref* psender)
{
	for (auto sp : m_array)
	{
		if (sp->GetName() == name)
		{
			sp->ObserverCallBack(psender);
		}
	}
}

void NotificationCenter::PostNotification(string name)
{
	for (auto sp:m_array)
	{
		if (sp->GetName()==name)
		{
			sp->ObserverCallBack();
		}
	}
}


至此,消息管理系統已然完善,代碼簡單就沒一一註釋了。
4. Test測試樣例
系統實現了,接下來就是測試了,首先class一個Sprite類,繼承自Ref基類:
Sprite.h:
#ifndef _SPRITE_H_
#define _SPRITE_H_
#pragma once

#include "Ref.h"
using namespace std;

class Sprite :public Ref, Blog
{
public:
	
	Sprite();
	~Sprite();
	 void test();
	 void dosomthing();
};

#endif

Sprite.cpp:
#include "Sprite.h"
#include <iostream>
#include"NotificationCenter.h"

Sprite::Sprite()
{
}


Sprite::~Sprite()
{
}
void Sprite::test()
{
	
	cout << "I am here"<<endl;
	this->dosomthing();
}
void Sprite::dosomthing()
{
	printf("I am here to doing somthing");
	return;
}

接着main函數:
// C++Test.cpp : 定義控制檯應用程序的入口點。
//
#include<unordered_map>
#include<map>
#include<set>
#include"Sprite.h"
#include"NotificationCenter.h"
using namespace std;
void MainTest()
{
	auto sprite=new Sprite();
	NotificationCenter::getInstance()->addObserver(dynamic_cast<Ref*>(sprite), "test", callfunc_selector(Sprite::test));
	NotificationCenter::getInstance()->PostNotification("test");
	delete sprite;
}

int _tmain(int argc, _TCHAR* argv[])
{
	MainTest();
	return 0;
}



運行圖:

附:同事吐槽我的這個機制,Ref基類完全是沒有任何意義的基類,僅僅只作爲強轉對象的目標類,還有什麼沒必要啥的,真是飽受詬病,其實我當時也只是想Ref都借(chao)鑑(xi)了,似乎可以把他們的內存管理機制也抄過來,所以當時是覺得Ref是可以繼續拓展功能的,然則發現bug之後,沒有去使用這個方式了,請移步下一篇升級版。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章