消息映射深度探索(4):职责链模式 - 使用虚函数替换映射表

来源:互联网 发布:保定seo价格 编辑:程序博客网 时间:2024/06/10 02:13

转自:http://blog.csdn.net/hjsunj/article/details/2028597

下面我们将介绍另一种实现消息映射的方式:职责链模式

#include <iostream>
#include <map>
#include <cassert>

#define PRINT( msg ) { std::cout << msg << std::endl; }
#define FUNC( func ) void func() { PRINT( #func##"()" ); }
#define MFUNC( class, func ) void func() { PRINT( #class##"::"###func##"()" ); }
#define VMFUNC( class, func ) virtual MFUNC( class, func )

enum MsgID {
    MsgID_1,
    MsgID_2,
};

namespace COR { // chain of responsibility
    class Wnd;
    typedef void (Wnd::*MemberFunc)();    

    class Wnd {
    public:
        virtual void HandleMsg( int id ) {
            switch ( id ) {
                case MsgID_1: Handle1(); break;
                case MsgID_2: Handle2(); break;
            }
        }

    private:
        MFUNC( Wnd, Handle1 );
        MFUNC( Wnd, Handle2 );
    };

    class MyWnd : public Wnd {
    public:
        virtual void HandleMsg( int id ) {
            switch( id ) {
                case MsgID_1: Handle1(); break;
                default: Wnd::HandleMsg( id );
            }
        }

    private:
        MFUNC( MyWnd, Handle1 );
    };    
}

namespace AutoTest {
    void TestCORMsgMap() {
        using namespace COR;
        Wnd* wnd = new MyWnd;
        wnd->HandleMsg( MsgID_1 );
        wnd->HandleMsg( MsgID_2 );
    }
}

void main() {
    AutoTest::TestCORMsgMap();
} 

原理

不需要消息映射表,而是利用虚函数HandleMsg()向父类递归查找,详情可参考《设计模式》职责链模式。

细节

1. 可以把switch...case用查找表替换掉,但绝非必要。通常使用此法是在有封装之必要时才会采取的措施,详情可参考 
http://blog.csdn.net/hjsunj/archive/2008/01/07/2028597.aspx
http://blog.csdn.net/hjsunj/archive/2008/01/11/2037354.aspx

2. 使用NVI模式(《Effective C++ 3rd》chapter35)让思路更加清晰,此时需借助查找表
将HandleMsg变为非虚函数:
void HandleMsg( int id ) {
    MemberFunc func = Lookup( id );
    if ( func != NULL ) {
        (this->*func)();
   }
}
virtual MemberFunc Lookup( int id ) {
    // 如果thisclass有id之处理函数,返回之   
    // 否则返回BaseClass::Lookup( id );
}

优缺点

1. 实现简单:不再需要定制宏,不再需要建立消息映射表,所需的只是重写虚函数。
2. 节省内存:由于不再需要为每个派生类准备查找表,节省内存是自然而然的事。
2. 效率低下: 通常使用虚函数的效率会高于查找表(《设计模式》p204),但那只对一次调用成立。职责链模式对虚函数递归调用,其时间开销必然要高于映射表方案的迭代查找。