• 2010-09-10

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

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/74698689.html

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

    分享到:

    历史上的今天:

    引用地址:

    评论

  • 我以前也搞java的现在转c++
    写了2年c++也不敢拿出代码现
    c++和java是两个世界,说实话相比之下java只是个玩具,思维深度和c++比起来永远稚嫩
    真想追求技术的话,搞游戏或服务器去吧,做这种所谓咨询耽误自己一辈子的技术梦

    好几年前就看过你的博客今天发个言
  • 那几个new,可能某些做服务器端程序的人会受不了. handlers 倒是可以做成static的.所有对象共用一份就可以了.
  • 我有兴趣想知道作为一个consultant,是如何persuade那些古董级C程序员放弃switch的. 你一说大家就觉得有道理了?还是用一步的一步的引导?或者大家只是假装觉得map好.
  • 在头文件中最好使用std::map而非map,否则会有影响的.比如与GDI++的头文件共用的时候,stl 与 GDI++的头文件有冲突.不过这种情况一般比较少见.
    回复eBen说:
    多谢提醒,已修改。
    2010-09-13 22:38:32
  • MsgHandler::open还是&MsgHandler::open? 我一般使用编译器来检查.VC6两种都可以. 没有仔细研究过.我是哪种能在gcc或高版本的vc下编译过就用哪种
    回复eBen说:
    改成&的版本了,兼容性好一些。
    2010-09-13 22:40:42
  • 应当是:map<, DispatchHandler*>.
    DispatchHandler 应当有一个virtual的析构函数.否则map里的指针指向的内存没有办法释放了.
    评论长度还有限制,我晕......
    回复eBen说:
    篇幅原因,构造和析构就省略了。
    2010-09-13 22:36:16