杂货边角(9):C++实现事件委托机制
2018-01-18 16:37
3955 查看
在设计模式中,根据耦合紧密度可以得到排序为:继承 > 依赖 > 组合/聚合 > 委托。其实个人感觉,事件委托机制说白了就是一个函数指针数组,通过注册绑定的函数,然后在特定的事件发生后触发遍历执行所有注册的函数,机制其实和C++运行库glibc中
所以归根结底,事件委托机制的关键便是函数指针注册的实现。不过再次可惜的是,C++中还是没有实现像C#的delegate委托机制,所以又得动手操作了。
0. C#事件委托机制的使用示例
先把《大话设计模式》中关于事件委托机制的实例摆上,方便理解。
现在有一个cat类,mouse类,现在要实现cat发出叫声后, mouse就开始奔跑。这里信息的传递显然可以排除继承、依赖关系的使用,那么采用“关联关系”呢?这里需要明确的一点是,面向对象设计是模拟现实世界中的信息交互的,“关联关系”虽然相比于“继承”而言是耦合度较低的联系,但是“关联”在现实世界中对应的关系是双方认识,在C++类中体现为在对方类中存在一个自己类的实例对象。
但是此时思考的问题变成了,如果在现实世界中我们作为造物主,要实现“猫叫鼠奔”的场景,难道需要猫和老鼠彼此认识吗?显然作为信息流入口的只是cat.shout()动作,而非cat本身,故而这里需要的是一个比“关联”关系更弱耦合的联系,这便是事件委托机制。
这时更好的设计模式,便是直接在cat.shout()函数内部埋下委托事件,即一旦启用cat.shout()函数立即将该信息通过内部的注册表发送给周边的老鼠,启动mouse.run()。
先来看一下采用“关联关系”实现“猫叫鼠跑”场景的代码示意
可以看到为了实现“猫叫鼠跑”,必须要让猫获取老鼠所有的信息,虽然猫的内部没有额外的处理老鼠信息的函数,但是直接将所有老鼠的信息直接暴露给猫,一旦这个猫想开外挂简直不要太容易。所以这种关联关系对于这个场景还是信息过量了。
再来看下用事件委托机制实现“猫叫鼠跑”场景
这样的设计看起来便是很舒服的,那么如何在C++实现事件委托机制呢?
1. C++实现事件委托机制
和C++实现反射机制一样,事件委托机制的实现关键也是在注册函数指针上。
先来看下函数指针以及配合类如何使用的代码示例,摘自http://blog.csdn.net/y1196645376/article/details/51408114
根据上述分析,采用STL::List作为容器,泛化无参数无返回值函数的使用场景,采用原型模式设计”无参数无返回值函数注册机“系统,这篇博主的代码质量很高,不重复造轮子摘录如下。
其代码的UML架构如下
delegate.h
test.cpp
crtbegin.o和
crtend.o收集当前程序中所有全局对象的初始化函数和析构函数,用以执行遍历操作一致。
所以归根结底,事件委托机制的关键便是函数指针注册的实现。不过再次可惜的是,C++中还是没有实现像C#的delegate委托机制,所以又得动手操作了。
0. C#事件委托机制的使用示例
先把《大话设计模式》中关于事件委托机制的实例摆上,方便理解。
现在有一个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++实现事件委托机制呢?
1. 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; }
相关文章推荐
- C++实现事件委托机制
- 实现C++中的事件委托机制
- 实现C++中的事件委托机制
- 用 C++ 实现 C# 中的 委托/事件 (4-functor1)
- C++实现委托与事件代理
- C++实现的委托机制(一)
- C++事件(Event)机制的实现
- C++事件(Event)机制的实现一例
- 用 C++ 实现 C# 中的 委托/事件 (5-functor2)
- C++ 事件机制实现
- C++事件(Event)机制的实现一例(转载)
- C++实现的委托机制(二)
- C++实现的委托机制(三)
- 在C++中实现事件(委托)
- C++实现委托机制(一)
- 用 C++ 实现 C# 中的 委托/事件 (1-delegateEMU.cpp)
- 用C++实现C#中的委托和事件
- C++实现事件机制
- C++ 事件机制实现
- 事件机制之C++实现