基于类型的消息分发实现

在陈硕的github中看到一段非常有意思的代码,可以实现根据消息类型分发到不同的回调函数(link)。代码里是用的Protobuf的反射,本文使用支持多基类的C++类反射实现文中的的反射来改写一下。

首先来定义接口,如果是下面的用例,使用一个类名为key,callback函数为value的hash表就很容易的实现了:

class Foo : public Object {}; void OnRecvFoo(Object *foo); dispatcher.Register("Foo", OnRecvFoo);

但是这样在OnRecvFoo中需要做类型转换,调用Register时也需要手动输入类名字符串,容易出错且麻烦,所以有了如下用例:

void OnRecvFoo(Foo* foo); dispatcher.Register<Foo>(OnRecvFoo);

下面来分析一下实现,首先定义接口:

class ObjectDispatcher { public: template <typename T> void Register(const CallbackFunc<T>& func); void OnReceive(Object *obj) const; };

Register使用带有模板参数的回调函数作为参数,底层消息系统调用OnReceive来分发消息。为了实现注册分发,需要建立一个hash表,key是消息的类型信息,value是带有模板参数的回调函数。由于value类型并不一致,为了放到hash表中,需要定义一个共同基类:

class ReceiveCallback { public: virtual ~ReceiveCallback() {}; virtual void OnReceive(Object *obj) = 0; };

然后定义一个带模板参数的派生类表示回调函数:

template <typename T> class ReceiveCallbackT : public ReceiveCallback { public: typedef boost::function<void (T*)> ObjectCallbackFunc; ReceiveCallbackT(const ObjectCallbackFunc& func) : m_func(func) { } virtual void OnReceive(Object *obj) { T *obj1 = dynamic_cast<T*>(obj); assert(obj1 != NULL); m_func(obj1); } protected: ObjectCallbackFunc m_func; };

在Dispatcher中添加一个hash表存储对应关系,并定义一个默认回调函数用于处理没有注册的消息:

class ObjectDispatcher { public: ObjectDispatcher() : m_default_callback(boost::bind(&ObjectDispatcher::DefaultObjectCallback, this, _1)) { } template <typename T> void Register(const typename ReceiveCallbackT<T>::ObjectCallbackFunc& func) { if (m_callbacks.count(&T::ms_classInfo) != 0) wximpl::LOG_INFO("ObjectDispatcher.Connect twice: %s.", T::ms_classInfo.GetClassName().c_str()); boost::shared_ptr<ReceiveCallbackT<T> > pc(new ReceiveCallbackT<T>(func)); m_callbacks[&T::ms_classInfo] = pc; } void OnReceive(Object *obj) const { CallbackMap::const_iterator itor = m_callbacks.find(obj->GetClassInfo()); if (itor != m_callbacks.end()) { itor->second->OnReceive(obj); } else { m_default_callback(obj); } } void DefaultObjectCallback(Object *obj) { wximpl::LOG_INFO("UnProcessed object :%s.", obj->GetClassInfo()->GetClassName().c_str()); } private: typedef std::map<const reflection::ClassInfo<Object>*, boost::shared_ptr<ReceiveCallback> > CallbackMap; CallbackMap m_callbacks; boost::function<void (Object *)> m_default_callback; };

这样的消息分发机制在一些通信系统中非常实用。

posted @ 2014-02-25 10:03  Echo.Zhao  阅读(995)  评论(0编辑  收藏  举报