ITPub博客

首页 > Linux操作系统 > Linux操作系统 > [转]一个用C++实现的Dispatcher

[转]一个用C++实现的Dispatcher

原创 Linux操作系统 作者:zuohongyoulan 时间:2011-05-05 13:11:02 0 删除 编辑
Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE又和一个团队合作,面前又摆着一堆分发的代码,不同的是,这次用的是C++
if (msg->id == "open") {
    MsgHandler handler(msg);
    handler.open();
} else if (msg->id == "close") {
    MsgHandler handler(msg);
    handler.close();
} else if (…) {
    …
} else {
    // exception handler
    …
}

不要问我为什么不是每个消息对应一种处理类,要是知道为什么,就不是遗留代码了。于是,我们尝试着用C++写了一个dispatcher。下面是这个dispatcher的声明:
#include

typedef void (MsgHandler::*handlerFunc)();

class MsgDispatcher {
public:
    ...
    void dispatch(Msg* msg);
private:
    std::map handlers;
};

因为要处理遗留代码,这里用到了指向成员函数的指针,也就提高了理解这段代码的门槛。具体实现如下:
void MsgDispatcher::dispatch(Msg* msg) {
    handlerFunc func = this->handlers[msg->id];
    if (func) {
        MsgHandler msgHandler(pkg);
        (msgHandler.*func)();
    } else {
        // exception handler
        …
    }
}

注册很简单:
handlers["open"] = &MsgHandler::open;
handlers["close"] = &MsgHandler::close;

 

 

 

 

 

遗留代码就是遗留代码,总会有一些让人意想不到的地方,原以为所有消息都是由一个类(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;
};

对于前面的两种类型,道理上来说,我们需要分别为两个类型(MsgHandlerMsgHandler2)分别编写对应的子类。不过,我们用的是C++,是的,模板:
template
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

class MsgDispatcher {
public:
    ...
    void dispatch(Msg* msg);
private:
    std::map 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::open);
handlers["close"] = new DispatchHandlerImpl(&MsgHandler2::close);

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

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

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12925485/viewspace-694497/,如需转载,请注明出处,否则将追究法律责任。

下一篇: [转]epoll模型
请登录后发表评论 登录
全部评论

注册时间:2008-09-18

  • 博文量
    24
  • 访问量
    37066