一个用C++实现的Dispatcher(二)

标签: dispatcher | 发表时间:2010-09-10 23:33 | 作者:dreamhead kevH
出处:http://dreamhead.blogbus.com

遗留代码就是遗留代码,总会有一些让人意想不到的地方,原以为所有消息都是由一个类(MsgHandler)处理的,可事实上,不是。
if (msg->id == "open") {
    MsgHandler handler(msg);
    handler.open();
} else if (msg->id == "close") {
    MsgHandler2 handler(msg);
    handler.close();
} else if (…) {
    …
} else {
    // exception handler
    …
}

上面的代码里面只有消息处理类的名字不同,其它的处理完全相同。不过,这样就让之前那个dispatcher就显得势单力薄。解决程序设计的问题,有一个很好用的处理手法:加个间接层。于是,
class DispatchHandler {
public:
    virtual void execute(Msg* msg) = 0;
};

对于前面的两种类型,道理上来说,我们需要分别为两个类型(MsgHandler和MsgHandler2)分别编写对应的子类。不过,我们用的是C++,是的,模板:
template<typename T>
class DispatchHandlerImpl : public DispatchHandler {
    typedef void (T::*Func)();
public:
    DispatchHandlerImpl(Func sourceHandler)
        :handler(sourceHandler) {}

    void execute(Msg* msg) {
        T msgHandler(msg);
        (msgHandler.*(this->handler))();
    }

private:
    Func handler;
};

原来的dispatcher也要相应的调整:
#include <map>

class MsgDispatcher {
public:
    ...
    void dispatch(Msg* msg);
private:
    std::map<string, DispatchHandler> handlers;
};

void MsgDispatcher::dispatch(Msg* msg) {
    DispatchHandler* handler = this->handlers[msg->id];
    if (handler) {
        handler->execute(msg);
    } else {
        // exception handler
        …
    }
}

对应的注册代码也就变成:
handlers["open"] = new DispatchHandlerImpl<MsgHandler>(&MsgHandler::open);
handlers["close"] = new DispatchHandlerImpl<MsgHandler2>(&MsgHandler2::close);

有代码洁癖的我们发现类名在这里重复了,于是,定义一个宏对其进行简化:
#define DISPATCH_HANDLER(className, funcName) \
  DispatchHandlerImpl <className>(&className::funcName)

handlers["open"] = new DISPATCH_HANDLER(MsgHandler, open);
handlers["close"] = new DISPATCH_HANDLER(MsgHandler2, close);

相关 [dispatcher] 推荐:

一个用C++实现的Dispatcher(一)

- kevH - 梦想风暴
又和一个团队合作,面前又摆着一堆分发的代码,不同的是,这次用的是C++:. 不要问我为什么不是每个消息对应一种处理类,要是知道为什么,就不是遗留代码了. 于是,我们尝试着用C++写了一个dispatcher. 下面是这个dispatcher的声明:. 因为要处理遗留代码,这里用到了指向成员函数的指针,也就提高了理解这段代码的门槛.

一个用C++实现的Dispatcher(二)

- kevH - 梦想风暴
遗留代码就是遗留代码,总会有一些让人意想不到的地方,原以为所有消息都是由一个类(MsgHandler)处理的,可事实上,不是. 上面的代码里面只有消息处理类的名字不同,其它的处理完全相同. 不过,这样就让之前那个dispatcher就显得势单力薄. 解决程序设计的问题,有一个很好用的处理手法:加个间接层.

一个用C++实现的Dispatcher(三)

- kevH - 梦想风暴
eBen给《一个用C++实现的Dispatcher(二)》提出了一些非常好的问题,修正了一些细节. 那几个new,可能某些做服务器端程序的人会受不了. handlers倒是可以做成static的.所有对象共用一份就可以了. 这个问题在实现这个dispatcher的时候,有人提出来过,但我依然坚持我的选择.