如何用c++表驅(qū)動替換if/else和switch/case語句
C++的表驅(qū)動法
目的:使用表驅(qū)動法,替換復(fù)雜的if/else和switch/case語句。
一、常用示例
以switch為例,常用示例如下:
Funcition() { switch (key) { case key1: statements 1; break; case key2: statements 2; break; ... case keyn: statements n; break; default: break; } }
上述switch代碼段,實際集成了3種類型邏輯:
1. 實現(xiàn)關(guān)鍵字的處理代碼;
2. 將關(guān)鍵字與處理代碼關(guān)聯(lián);
3. 以關(guān)鍵字選擇分支,執(zhí)行處理代碼;
我們將在一個switch代碼中維護3種變化。將1的處理代碼段,模塊化為函數(shù)后,變化點減少為2個。
在分支增加到幾十個時,代碼維護性變得很差;而且switch對非整數(shù)類型無能為力。
二、表驅(qū)動法
做法:
1. 將變化點2,做成一個[關(guān)鍵字:處理函數(shù)]映射結(jié)構(gòu)(推薦map容器),在獨立函數(shù)中賦值。
2. 將變化點3,做成一個查找關(guān)鍵字,執(zhí)行對應(yīng)函數(shù)的簡單函數(shù)
好處:
1. 獨立出“選擇分支”變化點,變?yōu)楣潭ǖ奶幚砹鞒獭?br />
2. 獨立出“關(guān)鍵字和處理函數(shù)的關(guān)聯(lián)”,易于維護。
限制條件:
1. 處理函數(shù)類型一樣(這在C++中不成問題);
2. 處理函數(shù)簡單,但每個函數(shù)有差異(如果處理較為復(fù)雜,請使用創(chuàng)建型設(shè)計模式)
擴展:
1. 對于處理函數(shù)由符合條件分支情況,變化點2使用list結(jié)構(gòu),按優(yōu)先級關(guān)聯(lián)處理函數(shù),使用 “職責鏈”形式的表驅(qū)動法。
三、C++實現(xiàn)注意
代碼:
// 3個文件,Client.cpp, TableDrave.h, TableDrive.cpp // vvvvv Client.cpp begin // ------------------------------------------------------------ // Name : Client.cpp // Description : 調(diào)用接口 // History : // ------------------------------------------------------------ #include "TableDrive.h" // ------------------------------------------------------------ int main() { TableDrive test; test.HandleKeyword(KEYWORD_A); test.HandleKeyword(KEYWORD_B); test.HandleKeyword(KEYWORD_C); test.HandleKeyword(KEYWORD_START); test.HandleKeyword(KEYWORD_D); return 0; } // ^^^^^ Client.cpp end // vvvvv TableDrive.h begin // ------------------------------------------------------------ // Name : TableDrive.h // Description : 表驅(qū)動頭文件 // History : // ------------------------------------------------------------ #ifndef _TEST_DRIVE_H #define _TEST_DRIVE_H #include <map> // ------------------------------------------------------------ // 測試用關(guān)鍵字 enum KEYWORD { KEYWORD_START = -1, KEYWORD_A = 0, KEYWORD_B, KEYWORD_C, KEYWORD_D, KEYWORD_END, }; // ------------------------------------------------------------ // 可以使用 std:: 單個引用 using namespace std; class TableDrive { public: // ------------------------------------------------------------ // Description : // 根據(jù)關(guān)鍵字,執(zhí)行處理函數(shù) // Parameters : // string keyword,關(guān)鍵字 // Return Value : // bool,true,函數(shù)執(zhí)行成功,false,找不到鍵字對應(yīng)的函數(shù),或函數(shù)執(zhí)行失敗 // Errors : // 無 // ------------------------------------------------------------ bool HandleKeyword(int keyword); // ------------------------------------------------------------ // Description : // 關(guān)聯(lián)關(guān)鍵字到處理函數(shù) // Parameters : // 無 // Return Value : // bool,true,正常,false,異常 // Errors : // 無 // ------------------------------------------------------------ bool MapKeyToHandle(); TableDrive(); ~TableDrive(); private: // vv 處理函數(shù),true,執(zhí)行成功,false,執(zhí)行失敗 bool HandleKeyA(); bool HandleKeyB(); bool HandleKeyC(); // ^^ private: // :TRICKY: 成員函數(shù)指針定義 typedef bool (TableDrive:: *PHandle)(void); map<int, PHandle> m_KeyToHandle; // 關(guān)鍵字對應(yīng)處理函數(shù) }; #endif // ^^^^^ TableDrive.h end // vvvvv TableDrive.cpp begin // ------------------------------------------------------------ // Name : TableDrive.cpp // Description : 表驅(qū)動實現(xiàn)文件 // History : // ------------------------------------------------------------ #include <stdio.h> #include "TableDrive.h" // ------------------------------------------------------------ // 根據(jù)關(guān)鍵字,執(zhí)行處理函數(shù) bool TableDrive::HandleKeyword(int keyword) { typedef map<int, PHandle>::const_iterator CI; CI iter = m_KeyToHandle.find(keyword); // 沒有搜索到關(guān)鍵字 if (m_KeyToHandle.end() == iter) { printf("\n @@ search Keyword %d fail!\n", keyword); return false; } // :TRICKY: 注意成員函數(shù)指針的引用格式 PHandle pFunction = iter->second; return (this->*pFunction)(); } TableDrive::TableDrive() { printf("\n vv TableDrive::TableDrive()\n"); MapKeyToHandle(); } TableDrive::~TableDrive() { printf("\n ^^ TableDrive::~TableDrive()\n"); } // ------------------------------------------------------------ // 關(guān)聯(lián)關(guān)鍵字到處理函數(shù) bool TableDrive::MapKeyToHandle() { m_KeyToHandle[KEYWORD_A] = &TableDrive::HandleKeyA; m_KeyToHandle[KEYWORD_B] = &TableDrive::HandleKeyB; m_KeyToHandle[KEYWORD_C] = &TableDrive::HandleKeyC; return true; } // 處理函數(shù) A bool TableDrive::HandleKeyA() { printf("\n ** A, HandleKeyA()\n\n"); return true; } bool TableDrive::HandleKeyB() { printf("\n ** B, HandleKeyB()\n\n"); return true; } bool TableDrive::HandleKeyC() { printf("\n ** C, HandleKeyC()\n\n"); return true; } // ^^^^^ TableDrive.cpp end
關(guān)注點:
主要關(guān)注3個點,維護第2、3點
1. HandleKeyword(),根據(jù)關(guān)鍵字,執(zhí)行處理函數(shù)。固定后基本不改變;
2. MapKeyToHandle(),關(guān)聯(lián)關(guān)鍵字到處理函數(shù);
3. Handle(),各個處理函數(shù)
成員函數(shù)指針使用注意
1. 聲明格式,與C相比,函數(shù)指針前要包含類域;
typedef bool (TableDrive:: *PHandle)();
2. 聲明位置,包含在類中,否則不能識別類域標志;
3. 賦值語法格式,與C相比,函數(shù)指針前要包含類域;
PHandle pFunction = &TableDrive::HandleKeyA;
4. 調(diào)用語法格式,與C相比,需要加上this,并以強制解引用方式調(diào)用;
(this->*pFunction)();
四、實用案例
1. 菜單調(diào)節(jié)。一個模塊,有幾十個菜單參數(shù)可以調(diào)節(jié),每個菜單調(diào)節(jié)的步進、范圍不同,但都是“觸發(fā)消息、調(diào)節(jié)數(shù)值”流程。
2. 按鍵響應(yīng)。多個按鍵,屬于“按鍵,執(zhí)行對應(yīng)處理函數(shù)”流程。
3. 鼠標操控。不同狀態(tài)下移動鼠標,屬于“狀態(tài)判斷、響應(yīng)鼠標處理函數(shù)”流程。
表驅(qū)動法
到此這篇關(guān)于使用c++表驅(qū)動法,替換復(fù)雜的if/else和switch/case語句的文章就介紹到這了,更多相關(guān)c++表驅(qū)動法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡單比較C語言中的execl()函數(shù)與execlp()函數(shù)
這篇文章主要介紹了C語言中的execl()函數(shù)與execlp()函數(shù)的簡單比較,是C語言入門學習中的基礎(chǔ)知識,需要的朋友可以參考下2015-08-08C++的STL中accumulate函數(shù)的使用方法
這篇文章主要介紹了C++的STL中accumulate的使用方法,accumulate作用是累加求和即自定義類型數(shù)據(jù)處理,下文具體的操作方法需要的小伙伴可以參考一下2022-03-03對比分析C語言中的gcvt()和ecvt()以及fcvt()函數(shù)
這篇文章主要介紹了對比分析C語言中的gcvt和ecvt以及fcvt函數(shù),都是將數(shù)字轉(zhuǎn)化為字符串,注意其之間的功能區(qū)別,需要的朋友可以參考下2015-08-08