一估盘、 假設(shè)有一個(gè)程序,需要處理其他程序發(fā)送的消息剔氏,消息類型是字符串塑猖,每個(gè)消息都需要一個(gè)函數(shù)進(jìn)行處理竹祷。第一印象,我們可能會(huì)這樣處理:
上面的消息類型取自sip協(xié)議(不完全相同羊苟,sip協(xié)議借鑒了http協(xié)議)塑陵,消息類型可能還會(huì)增加〖眨看著常常的流程可能有點(diǎn)累猿妈,檢測(cè)一下中間某個(gè)消息有沒有處理也比較費(fèi)勁吹菱,而且巍虫,沒增加一個(gè)消息,就要增加一個(gè)流程分支鳍刷。
按照表驅(qū)動(dòng)編程的思路占遥,可能會(huì)這樣設(shè)計(jì):?
復(fù)雜一點(diǎn)的表驅(qū)動(dòng) :考慮一個(gè)消息(事件)驅(qū)動(dòng)的系統(tǒng),系統(tǒng)的某一模塊需要和其他的幾個(gè)模塊進(jìn)行通信输瓜。它收到消息后瓦胎,需要根據(jù)消息的發(fā)送方,消息的類型尤揣,自身的狀態(tài)搔啊,進(jìn)行不同的處理。比較常見的一個(gè)做法是用三個(gè)級(jí)聯(lián)的switch分支實(shí)現(xiàn)通過硬編碼來實(shí)現(xiàn):
這種方法的缺點(diǎn):
1北戏、可讀性不高:找一個(gè)消息的處理部分代碼需要跳轉(zhuǎn)多層代碼负芋。
2、過多的switch分支嗜愈,這其實(shí)也是一種重復(fù)代碼旧蛾。他們都有共同的特性,還可以再進(jìn)一步進(jìn)行提煉蠕嫁。
3锨天、可擴(kuò)展性差:如果為程序增加一種新的模塊的狀態(tài),這可能要改變所有的消息處理的函數(shù)剃毒,非常的不方便病袄,而且過程容易出錯(cuò)。
4赘阀、程序缺少主心骨:缺少一個(gè)能夠提綱挈領(lǐng)的主干益缠,程序的主干被淹沒在大量的代碼邏輯之中。
用表驅(qū)動(dòng)法來實(shí)現(xiàn):
根據(jù)定義的三個(gè)枚舉:模塊類型纤壁,消息類型左刽,自身模塊狀態(tài),定義一個(gè)函數(shù)跳轉(zhuǎn)表:
這種方法的好處:
1酌媒、提高了程序的可讀性欠痴。一個(gè)消息如何處理迄靠,只要看一下驅(qū)動(dòng)表就知道,非常明顯喇辽。
2掌挚、減少了重復(fù)代碼。這種方法的代碼量肯定比第一種少菩咨。為什么吠式?因?yàn)樗岩恍┲貜?fù)的東西:switch分支處理進(jìn)行了抽象,把其中公共的東西——根據(jù)三個(gè)元素查找處理方法抽象成了一個(gè)函數(shù)GetFunFromDriver外加一個(gè)驅(qū)動(dòng)表抽米。
3特占、可擴(kuò)展性。注意這個(gè)函數(shù)指針云茸,他的定義其實(shí)就是一種契約是目,類似于java中的接口,c++中的純虛函數(shù)标捺,只有滿足這個(gè)條件(入?yún)ⅲ?a target="_blank" rel="nofollow">返回值)懊纳,才可以作為一個(gè)事件的處理函數(shù)。這個(gè)有一點(diǎn)插件結(jié)構(gòu)的味道亡容,你可以對(duì)這些插件進(jìn)行方便替換嗤疯,新增,刪除闺兢,從而改變程序的行為茂缚。而這種改變,對(duì)事件處理函數(shù)的查找又是隔離的(也可以叫做隔離了變化)列敲。阱佛、
4、程序有一個(gè)明顯的主干戴而。
5凑术、降低了復(fù)雜度。通過把程序邏輯的復(fù)雜度轉(zhuǎn)移到人類更容易處理的數(shù)據(jù)中來所意,從而達(dá)到控制復(fù)雜度的目標(biāo)淮逊。
二、假設(shè)你在寫一個(gè)計(jì)算醫(yī)療保險(xiǎn)費(fèi)率的程序扶踊,這些費(fèi)率隨著年齡泄鹏、性別、婚姻狀況秧耗、以及吸煙與否的不同情況而變化的备籽。你寫出的代碼會(huì)不會(huì)是這樣?
很簡(jiǎn)單是不是??? 很繁瑣有木有车猬?你能想象霉猛,把這個(gè)題目做完需要多大的代碼量。
好珠闰,現(xiàn)在看看表驅(qū)動(dòng)法的解決這類邏輯控制結(jié)構(gòu)惜浅。
首先,我們需要做的是把這些費(fèi)率存入所有元素索引的數(shù)組里面伏嗜,用簡(jiǎn)單形象的描述就是坛悉,你需要定義一個(gè)類型,像這樣:
對(duì)承绸,它僅僅是一個(gè)枚舉類型裸影,上述只定義了兩個(gè)類型, 我們還需要定義一個(gè)性別類型八酒,在此就不再重復(fù)空民。
現(xiàn)在數(shù)據(jù)類型已經(jīng)定義好了刃唐,現(xiàn)在差的就是數(shù)據(jù)了羞迷,數(shù)據(jù)可以從數(shù)據(jù)庫(kù)查出,也可從文件讀出画饥,那就要看你怎么選擇了衔瓮,
下面定義一個(gè)方法:
我們現(xiàn)在需要做的,假如保險(xiǎn)人的信息是這樣的:18歲抖甘,單身热鞍,吸煙,女衔彻。
就像這樣薇宠,優(yōu)雅的代碼展示:
接下來可以根據(jù)是否吸煙,婚姻狀態(tài)艰额,性別澄港,年齡構(gòu)建一個(gè)數(shù)組,進(jìn)行查表柄沮。
1.1.3 分段查找
?通過確定數(shù)據(jù)所處的范圍確定分類(下標(biāo))回梧。有的數(shù)據(jù)可分成若干區(qū)間,即具有階梯性祖搓,如分?jǐn)?shù)等級(jí)狱意。此時(shí)可將每個(gè)區(qū)間的上限(或下限)存到一個(gè)表中,將對(duì)應(yīng)的值存到另一表中拯欧,通過第一個(gè)表確定所處的區(qū)段详囤,再由區(qū)段下標(biāo)在第二個(gè)表里讀取相應(yīng)數(shù)值。注意要留意端點(diǎn)镐作,可用二分法查找藏姐,另外可考慮通過索引方法來代替蚓再。
? ? ?如根據(jù)分?jǐn)?shù)查績(jī)效等級(jí):
上述兩張表(數(shù)組)也可合并為一張表(結(jié)構(gòu)體數(shù)組),如下所示:
該表結(jié)構(gòu)已具備的數(shù)據(jù)庫(kù)的雛形包各,并可擴(kuò)展支持更為復(fù)雜的數(shù)據(jù)摘仅。其查表方式通常為索引查找,偶爾也為分段查找问畅;當(dāng)索引具有規(guī)律性(如連續(xù)整數(shù))時(shí)娃属,退化為直接查找。
? ? ?使用分段查找法時(shí)應(yīng)注意邊界护姆,將每一分段范圍的上界值都考慮在內(nèi)矾端。找出所有不在最高一級(jí)范圍內(nèi)的值,然后把剩下的值全部歸入最高一級(jí)中卵皂。有時(shí)需要人為地為最高一級(jí)范圍添加一個(gè)上界秩铆。
? ? ?同時(shí)應(yīng)小心不要錯(cuò)誤地用“<”來代替“<=”。要保證循環(huán)在找出屬于最高一級(jí)范圍內(nèi)的值后恰當(dāng)?shù)亟Y(jié)束灯变,同時(shí)也要保證恰當(dāng)處理范圍邊界殴玛。
1.2.1 字符統(tǒng)計(jì)
? ? ?問題:統(tǒng)計(jì)用戶輸入的一串?dāng)?shù)字中每個(gè)數(shù)字出現(xiàn)的次數(shù)。
? ? ?普通解法主體代碼如下:
這種解法的缺點(diǎn)顯而易見添祸,既不美觀也不靈活滚粟。其問題關(guān)鍵在于未將數(shù)字字符與數(shù)組aDigitCharNum下標(biāo)直接關(guān)聯(lián)起來。
? ? ?以下示出更簡(jiǎn)潔的實(shí)現(xiàn)方式:?
上述實(shí)現(xiàn)考慮到0也為數(shù)字字符刃泌。該解法也可擴(kuò)展至統(tǒng)計(jì)所有ASCII可見字符凡壤。
1.2.7 消息處理
? ? ?問題:終端輸入不同的打印命令,調(diào)用相應(yīng)的打印函數(shù)耙替,以控制不同級(jí)別的打印亚侠。
? ? ?這是一段消息(事件)驅(qū)動(dòng)程序。本模塊接收其他模塊(如串口驅(qū)動(dòng))發(fā)送的消息俗扇,根據(jù)消息中的打印級(jí)別字符串和開關(guān)模式硝烂,調(diào)用不同函數(shù)進(jìn)行處理。常見的實(shí)現(xiàn)方法如下:
搬運(yùn)自:C語(yǔ)言表驅(qū)動(dòng)法編程實(shí)踐 - clover_toeic - 博客園
數(shù)據(jù)驅(qū)動(dòng)編程與表驅(qū)動(dòng)法(多if-else結(jié)構(gòu)精簡(jiǎn)) - CSDN博客