一、引入:最近在學習一個執行體庫的封裝,裏面線程間的通信使用的是基於消息循環機制的消息通信。
稍微講下這套通信機制的封裝:線程A擁有一個消息隊列queue,其他的線程B、C、D...如果想要和線程A通信,就可以向queue中放消息。顯然該隊列是一個生產者/消費者模型(單讀多寫)。
二、回到主題:好,現在開始考慮:線程A需要處理多種消息類型,而每種消息類型的處理方式可能不同,問題的解決方法最簡單的就是使用switch/case語句
switch(msg)
{
case msgB:
。。
case msgC:
。。
case msgD:
。。
}
但是,當我們的程序需要增加新的消息時,就需要在switch/case 結構中添加新的case語句,這顯然就破壞了代碼的封閉性,不符合面向對象的思想。
三、用面向對象的方法消除switch/case :
思路:
1、維護一個消息管理器,實際上就是一張2維表,表中的一條記錄表示:消息B對應的處理對象MsgBProcessor * pBPro;
2、對外,我們提供表的註冊方法(添加一種消息類型和其對應的處理對象):Rigister
來看一個具體實現:
1、2維表的使用
std::map<unsigned long MsgTypeId,MessageProcessor *> messageMappingTable;
DispatchMessage(Message * pMsg)
{
std::map<unsigned long MsgTypeID, MessageProcessor *>::iterator it;
it = messageMappingTable.find(pMsg->MsgTypeID);
if(it->second != 0)
{
it->second->Notify(pMsg); //Notify()就是不同消息的處理對象處理消息業務邏輯的具體實現
}
}
注意:所有的消息處理對象必須要繼承自一個接口,並且在該接口中要提供一個統一的消息處理業務邏輯的入口Notify(pMsg)
2、2維表的註冊:
Rigister(unsigned long MsgTypeId, MessageProcessor * pMsgPro)
{
messageMappingTable[MsgTypeId] = pMsgPro;
}
總結,消除switch/case方法實現的要點:
1、在分配消息之前,將消息的類型ID和處理此類消息的對象註冊到消息管理器中
2、接受到消息並準備分配消息的時候,首先根據消息類型的ID號去消息管理器中查找處理處理對象
3、所有消息處理類都要繼承自一個接口,這樣在分配函數中,才能統一的調用消息處理方法