杂货边角(9):C++实现事件委托机制

在设计模式中,根据耦合紧密度可以得到排序为:继承 > 依赖 > 组合/聚合 > 委托。其实个人感觉,事件委托机制说白了就是一个函数指针数组,通过注册绑定的函数,然后在特定的事件发生后触发遍历执行所有注册的函数,机制其实和C++运行库glibc中crtbegin.ocrtend.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;
}

这里写图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值