消除switch/case語句,不破壞代碼的封閉性,使程序結構更符合面向對象思想(二)

在 “消除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;  //消息管理器

2、消息的註冊:在消除switch/case語句...(一)中,我曾經說過,消息分配這整個業務邏輯是建立在一個基於消息循環機制的線程通信框架上的。

我們暫且給這框架的主要實現類命名爲: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.....


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章