項目經過長期多人的維護,所謂人多手雜,出現不少過多過長的switch-case分支,或者多重switch-case嵌套。每每添加功能,我都會緊皺眉頭,然后帶着罪惡感向已經成百上千行的函數里再添上一個case分支,然后糾結地收工了事。
於是乎,在我的內心深處,switch-case儼然成了代碼壞味道的代名詞,寫代碼時總小心翼翼地避開它們,可往往又事與願違。
事實上,switch-case語句並不是代碼壞味道的根源,壞味道來自糟糕的結構設計,過多的switch-case分支,多重switch-case嵌套,這些都將導致代碼可讀性下降,維護困難易出錯。
對於分支有多又長的switch-case分支,可是使用表驅動方法或者在特定情況下可以采用表驅動方法結合事件機制進行分解。
對於表驅動方法,可用數組或std::map將case判定常量映射到相應的處理函數。核心代碼實現類似如下:
// 分支判定枚舉
enum CASE
{
_CASE_A,
...
_CASE_X,
_CASE_AMOUNT // 分支總數
};
// 處理函數類型
typedef void (*HANDLER)(void);
// 映射
HANDLE handlers[_CASE_AMOUNT] =
{
&HandlerA,
...
&HandlerX
};
bool handler(UINT uEvent)
{
if (uEvent < _CASE_AMOUNT)
{
(*handlers[uEvent])();
return true;
}
return false;
}
優點:條理清晰易於閱讀。
缺點:要增添很多處理函數,且不便於跟蹤調試。
對於在一個公共對象里使用switch-case分支集中處理大量與該對象無緊密邏輯關聯事件的情況。可通過在公共基類中使用事件處理機制,實現事件與監聽器(與事件相關的對象,如窗口)的映射,事件的分配處理。相關代碼如下:
class CBase
{
...
public:
// 添加事件監聽器
static bool AddEventListener(UINT uEvent, CBase* pListener);
// 移除事件監聽器
static bool RemoveEventListener(UINT uEvent, CBase* pListener);
// 將事件給相應監聽器處理
static void DispatchEvent(UINT uEvent);
// 處理事件,該虛函數由監聽器實現
virtual void OnEvent(UINT uEvent, int nParam) {}
...
private:
// 事件與監聽器的映射,多個監聽器可監聽同一個事件
static std::multimap<UINT, CBase*> m_mmapEventListener;
...
}
對於事件處理機制,在Java等語言中有大量使用,這里就不貼一大段代碼了。
優點:邏輯性強,耦合度低,符合開放封閉原則。
缺點:事件分配時效率較switch-case分支低。
