在设计模式中,根据耦合紧密度可以得到排序为:继承 > 依赖 > 组合/聚合 > 委托。其实个人感觉,事件委托机制说白了就是一个函数指针数组,通过注册绑定的函数,然后在特定的事件发生后触发遍历执行所有注册的函数,机制其实和C++运行库glibc中crtbegin.o
和crtend.o
收集当前程序中所有全局对象的初始化函数和析构函数,用以执行遍历操作一致。
所以归根结底,事件委托机制的关键便是函数指针注册的实现。不过再次可惜的是,C++中还是没有实现像C#的delegate委托机制,所以又得动手操作了。
先把《大话设计模式》中关于事件委托机制的实例摆上,方便理解。
现在有一个cat类,mouse类,现在要实现cat发出叫声后, mouse就开始奔跑。这里信息的传递显然可以排除继承、依赖关系的使用,那么采用“关联关系”呢?这里需要明确的一点是,面向对象设计是模拟现实世界中的信息交互的,“关联关系”虽然相比于“继承”而言是耦合度较低的联系,但是“关联”在现实世界中对应的关系是双方认识,在C++类中体现为在对方类中存在一个自己类的实例对象。
但是此时思考的问题变成了,如果在现实世界中我们作为造物主,要实现“猫叫鼠奔”的场景,难道需要猫和老鼠彼此认识吗?显然作为信息流入口的只是cat.shout()动作,而非cat本身,故而这里需要的是一个比“关联”关系更弱耦合的联系,这便是事件委托机制。
这时更好的设计模式,便是直接在cat.shout()函数内部埋下委托事件,即一旦启用cat.shout()函数立即将该信息通过内部的注册表发送给周边的老鼠,启动mouse.run()。
先来看一下采用“关联关系”实现“猫叫鼠跑”场景的代码示意
class Cat
{
private string name;
public Cat(string name)
{
this.name = name;
}
private IList<Mouse*> registedMouses;
public void Regist(Mouse* object)
{
registMouses.add(object);
}
public void Shout()
{
Console.WriteLine("喵喵我{0}来捉各位了", name);
if (registMouses.length() != 0)
{
foreach it in registMouses:
it->Run();
}
}
}
class Mouse
{
private string name;
public Mouse(string name)
{
this.name = name;
}
public void Run()
{
Console.WriteLine("老猫来了,{0}快跑!", name);
}
}
可以看到为了实现“猫叫鼠跑”,必须要让猫获取老鼠所有的信息,虽然猫的内部没有额外的处理老鼠信息的函数,但是直接将所有老鼠的信息直接暴露给猫,一旦这个猫想开外挂简直不要太容易。所以这种关联关系对于这个场景还是信息过量了。
再来看下用事件委托机制实现“猫叫鼠跑”场景
class cat
{
private string name;
public Cat(string name)
{
this.name = name;
}
public delegate void CatShoutEventHandler(); //声明委托类型CatShoutEventHandler
/*这里需要注意的便是CatShoutEventHandler的声明类型为无参数、无返回值类型,这决定了改类注册
**机能注册的函数也只能是void xx(void)类型,原理可以参考此前的反射机制的注册机map声明
*/
public event CatShotEventHandler CatShout; //声明事件CatShout对象
public void Shout()
{
Console.WriteLine("喵喵我{0}来捉各位了", name);
if (CatShout != NULL)
{
CatShout(); //当猫叫启动,如果CatShout注册机中有对象登记,则执行通知
}
}
}
class Mouse
{
private string name;
public Mouse(string name)
{
this.name = name;
}
public void Run()
{
Console.WriteLine("老猫来了,{0}快跑!", name);
}
}
static void Main(string[] args)
{
Cat cat = new Cat("Tom");
Mouse mouse1 = new Mouse("Jerry");
Mouse mouse1 = new Mouse("John");
cat.CatShout += new Cat.CatShoutEventHandler(mouse1.Run);
cat.CatShout += new Cat.CatShoutEventHandler(mouse2.Run);
cat.Shout();
Console.Read();
}
这样的设计看起来便是很舒服的,那么如何在C++实现事件委托机制呢?
和 C++实现反射机制一样,事件委托机制的实现关键也是在注册函数指针上。
先来看下函数指针以及配合类如何使用的代码示例,摘自http://blog.csdn.net/y1196645376/article/details/51408114
#include <iostream>
#include <cstdio>
using namespace std;
void NormalFunc()
{
printf("这里是普通函数\n");
}
class A
{
public:
static void StaticFunc()
{
printf("这里是成员静态函数\n");
}
void MemberFunc()
{
printf("这里是成员非静态函数\n");
}
};
int main()
{
//普通函数
typedef void(*NormalFuncp)();
//成员函数
typedef void(A::*MemberFuncp)();
NormalFuncp fun1 = NormalFunc;
MemberFuncp fun2 = &A::MemberFunc;
NormalFuncp fun3 = A::StaticFunc;
A a;
fun1();
(a.*fun2)(); //类的成员函数调用规范,使用".*"
fun3();
return 0;
}
根据上述分析,采用STL::List作为容器,泛化无参数无返回值函数的使用场景,采用原型模式设计”无参数无返回值函数注册机“系统,这篇博主的代码质量很高,不重复造轮子摘录如下。
其代码的UML架构如下
delegate.h
#ifndef _DELEGATE_H_
#define _DELEFATE_H_
#include <typeinfo>
#include <list>
using namespace std;
class IDelegate
{
public:
virtual ~IDelegate() { }
virtual bool isType(const std::type_info& _type) = 0;
virtual void invoke() = 0;
virtual bool compare(IDelegate *_delegate) const = 0;
};
class CStaticDelegate : public IDelegate
{
public:
typedef void (*NormalFunPtr)();
CStaticDelegate(NormalFunPtr _func):mFun(_func) {}
virtual bool isType(const std::type_info& _type)
{
return typeid(CStaticDelegate) == _type;
}
virtual void invoke()
{
mFun();
}
virtual bool compare(IDelegate* _delegate) const
{
if ( 0 == _delegate || !_delegate->isType( typeid(CStaticDelegate) ) )
return false;
CStaticDelegate* cast = static_cast<CStaticDelegate*>(_delegate);
return cast->mFun == mFun;
}
private:
NormalFunPtr mFun;
};
/*注册类非静态函数成员的委托,非静态函数成员的函数指针为void (ClassName::*FunName)();
**这里ClassName不确定,所以要么采用宏,要么采用模板类,这里采用模板类
*/
template<class T>
class CMethodDelegate : public IDelegate
{
public:
typedef void (T::*Method)();
CMethodDelegate(T* _object, Method _method): mObject(_object), mMethod(_method) {}
virtual bool isType (const std::type_info& _type)
{
return typeid(CMethodDelegate<T>) == _type;
}
virtual void invoke()
{
(mObject->*mMethod)();
}
virtual bool compare( IDelegate* _delegate) const
{
if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<T>)) )
return false;
CMethodDelegate<T>* cast = static_cast<CMethodDelegate<T>*>(_delegate);
return cast->mObject == mObject && cast->mMethod == mMethod;
}
private:
T* mObject;
Method mMethod;
};
inline IDelegate* newDelegate(void (*_func)() )
{
return new CStaticDelegate(_func);
}
template<class T>
inline IDelegate* newDelegate( T* _object, void (T::*_method)() )
{
return new CMethodDelegate<T>(_object, _method);
}
class CMultiDelegate
{
public:
typedef std::list<IDelegate*> ListDelegate;
typedef ListDelegate::iterator ListDelegateIterator;
typedef ListDelegate::const_iterator ConstListDelegateIterator;
CMultiDelegate() {}
~CMultiDelegate() {clear();}
bool empty() const
{
for (ConstListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); iter++)
{
if (*iter) return false;
}
return true;
}
void clear()
{
for (ListDelegateIterator iter = mListDelegates.begin(); iter!=mListDelegates.end(); iter++)
{
if (*iter)
{
delete (*iter);
(*iter) = 0;
}
}
}
/*重载了 += 表示向这个委托注册一个函数指针,这个方法会自动判重,如果重复了就不会向里面添加。*/
CMultiDelegate& operator+= (IDelegate* _delegate)
{
for (ListDelegateIterator iter = mListDelegates.begin(); iter!= mListDelegates.end(); ++iter)
{
if ((*iter) && (*iter)->compare(_delegate))
{
delete _delegate;
return *this;
}
}
mListDelegates.push_back(_delegate);
return *this;
}
/*重载了 -= 表示向这个委托注销一个函数指针,如果这个函数指针不存在就什么也不执行。*/
CMultiDelegate& operator-= (IDelegate* _delegate)
{
for (ListDelegateIterator iter = mListDelegates.begin(); iter!= mListDelegates.end(); ++iter)
{
if ((*iter) && (*iter)->compare(_delegate))
{
if ((*iter) != _delegate) delete (*iter); //如果是指向同一个IDelegate对象,即*iter=_delegate, 切勿重复删除
(*iter) = 0;
break;
}
}
delete _delegate;
return *this;
}
/*重载了 () 表示当作函数调用启动这个委托,内部就是将所有函数指针指向的函数都运行一遍。*/
void operator() ( )
{
ListDelegateIterator iter = mListDelegates.begin();
while (iter != mListDelegates.end())
{
if ( 0 == (*iter))
{
iter = mListDelegates.erase(iter);
}
else
{
(*iter)->invoke();
++iter;
}
}
}
private: //堵死这两种带参构造函数
CMultiDelegate (const CMultiDelegate& _event) { }
CMultiDelegate& operator= (const CMultiDelegate& _event) { }
private:
ListDelegate mListDelegates;
};
#endif
test.cpp
#include "delegate.h"
#include <iostream>
#include <cstdio>
using namespace std;
void NormalFunc()
{
printf("这里是普通函数\n");
}
class A
{
public:
int i;
A(int in):i(in) { }
static void StaticFunc()
{
printf("这里是成员静态函数\n");
}
void MemberFunc()
{
printf("这里是成员非静态函数%d\n", i);
}
};
int main()
{
//普通函数
typedef void(*NormalFuncp)();
//成员函数
typedef void(A::*MemberFuncp)();
NormalFuncp fun1 = NormalFunc;
MemberFuncp fun2 = &A::MemberFunc;
NormalFuncp fun3 = A::StaticFunc;
A a(10);
fun1();
(a.*fun2)();
fun3();
CMultiDelegate onClick;
onClick += newDelegate(NormalFunc);
onClick += newDelegate(&A(100), &A::MemberFunc);
onClick();
return 0;
}