在 “消除switch/case语句,不破坏代码的封闭性,使程序结构更符合面向对象思想(一)”中,我们曾讨论过维护一个消息管理器来记录不同消息和它对应的消息处理类。
但是,这种实现方式存在一个问题,考虑下:如果我们项目的业务逻辑很复杂,比如需要处理100多个消息类型,那我们就需要实现100多个消息处理类,维护这么多个消息处理类是相当麻烦的。怎么办?
思路:我们只能采取一种折中的方法,即把所有的消息处理类变成消息处理函数,然后把他们放到一个类中(All In One)统一管理,新添加一个消息,就要在该类中添加相应的处理函数。这种方法不太符合面向对象的思想,但从实际的变成角度来看,这样做可以大大减少类的数量,更容易维护。
好了,开始讲具体的实现:
1、消息处理器现在记录的是:消息类型ID 和 处理这个消息的成员函数的地址
2、成员函数必须要有它自己的对象来调用,所以我们还要保存一个指针用来指向该All In One的消息处理类
1、先来看看新版本中,消息管理器的实现:
typedef CStatus (CMessageProcessor:: *MsgProCallBackFunc)(CMessage * pMsg); //消息处理的成员函数 CMessageProcessorAllInOne * pMsgPro; //消息处理成员函数的调用者 std::map<unsigned long MsgTypeID, MsgProCallBackFunc> MsgManagerTable; //消息管理器
我们暂且给这框架的主要实现类命名为:MessageLoopManager,OK,现在开始讲消息注册的实现
class CMessageProcessorAllInOne { virtual CMessageProceesorAllInOne(CMessageLoopManager * pMsgLoopMgr, void * pContext) { pMsgLoopMgr->Register(MSG_B,(MsgProCallBackFunc)&(CMessageProcessorAllInOne::On_MsgB));pMsgLoopMgr->Register(MSG_B,(MsgProCallBackFunc)&(CMessageProcessorAllInOne::On_MsgC));}CStatus On_MsgB(CMessage * pMsg){... ...}CStatus On_MsgC(CMessage * pMsg){... ...}... ...};
3、消息的分配
DispatchMessage(CMessage * pMsg) { std::map<...>::iterator it; it = MsgManagerTable.find(pMsg->MsgTypeID); MsgProCallBackFunc * pFunc = it->second; return (pMsgPro->*pFunc)(pMsg); }
消除switch/case语句,不破坏代码的封闭性,使程序结构更符合面向对象思想(一)
消除switch/case语句,不破坏代码的封闭性,使程序结构更符合面向对象思想(二)
(一)更符合面向对象思想,且真正做到了不破坏代码的封闭性,每次想要添加一个新的消息,可以直接派生出一个新的消息类。但如本问所述,当消息太多时,就会导致需要创建的消息类太多,增加了维护成本。而在本文所讨论的方法中,又破坏了代码封闭性。这实际上是一种悖论,正所谓甘蔗不能两头甜,
所以具体使用(一)还是(二)我们要根据项目中具体情况而定,如果你用到的消息类型不多,你完全可以选用方法(一)来实现。反之ba la ba la.....