什么是表驅(qū)動法
我認(rèn)為,表驅(qū)動法,字如其名。就是用表格自身的邏輯來代替代碼里的條件判斷硬邏輯。
舉例如下:
如果,我們需要實(shí)現(xiàn)一個(gè)收費(fèi)系統(tǒng)。該系統(tǒng)根據(jù)人員工種與年齡兩個(gè)維度進(jìn)行收費(fèi)。如果要進(jìn)行硬編碼,很簡單,就挨個(gè)寫邏輯就好了。比如:
if(員工.工種 === 工種1){
if(員工.年齡 < 20){
收費(fèi)100
} else if(員工.年齡 < 40){
收費(fèi)200
} //等等
} else if(員工.工種 === 工種2){
//另一種情況
}
明顯的看到,硬編碼就是簡單的邏輯梳理。可是,這樣的寫法不具備好的擴(kuò)展性,如果要新增一個(gè)工種,就是更多的if-else的堆砌,可讀性極差。
而表驅(qū)動法,使用了表天生所具有的邏輯性。比如:
年齡\工種 | 工種1 | 工種2 |
---|---|---|
20 | 100 | 200 |
40 | 150 | 250 |
我們從這個(gè)表可以飛快的讀取到自己想要的信息,遠(yuǎn)比if-else描述的邏輯清晰有力易擴(kuò)展。
表驅(qū)動法的所有使用技巧,都是圍繞以下兩點(diǎn):
- 如何維護(hù)一個(gè)表
- 如何從自己拿到的信息映射的表上,取得自己想要的表里的信息
(未完待續(xù)。。。)
2018/2/14 更新
像上圖所示的表,我們可以使用一個(gè)對象去儲存他,之所以不使用二維數(shù)組是因?yàn)閿?shù)組沒有確定的key值,而數(shù)組的下標(biāo)對于使用者來講是無意義的。
var table = {
工種1: {
20歲: 100元,
40歲: 150元
},
工種2: {
20歲: 200元,
40歲: 250元
}
}
當(dāng)我們維護(hù)這樣一個(gè)對象之后,就可以簡單的去得到對應(yīng)工種與年齡的價(jià)格,例如:
var 價(jià)格 = table[工種][年齡]
維護(hù)數(shù)據(jù)的時(shí)候只需要維護(hù)這個(gè)邏輯清晰的table對象。
當(dāng)然,直接這樣去訪問這個(gè)表,寫法很不友好,我們可以把他封裝成一個(gè)函數(shù),供別人調(diào)用。這樣,使用者就不需要關(guān)心工種和年齡這兩個(gè)變量到底是哪個(gè)在前,哪個(gè)在后了。
上面說到我們使用表驅(qū)動法要思考兩個(gè)問題,一是如何構(gòu)建一個(gè)表,二是如何訪問這個(gè)表。第一點(diǎn)如何構(gòu)造一個(gè)表在我看來比較大同小異,再次不多介紹。主要討論一下如何訪問一個(gè)表。訪問方法大概有以下幾種:
- 直接通過鍵值訪問表。如,構(gòu)造一個(gè)對象table,以月份作為key,每個(gè)月的天數(shù)作為key對應(yīng)的值。則,每次訪問時(shí),直接使用table[月份]。
- 抽象表的鍵值。如,對于不同年齡階段(而不是確認(rèn)的年齡點(diǎn))的人有不同動作。可以通過將年齡階段這個(gè)區(qū)間抽象一層,轉(zhuǎn)換為特定的鍵值。
在代碼大全里還提出了兩種常見狀況,索引訪問表和階梯訪問表。
索引訪問表
索引訪問表的核心就是建立一張索引表,然后通過索引指向我們最終要查找的數(shù)據(jù)。
這樣的方式有兩個(gè)優(yōu)點(diǎn):
- 對于一些創(chuàng)建數(shù)組時(shí)需要指定數(shù)組大小的語言來講,會節(jié)省內(nèi)存
- 可以方便的通過更改索引表與索引查詢方法去換一種方式查詢數(shù)據(jù)
階梯訪問表
階梯訪問表所處理的問題的key值是一個(gè)連續(xù)的范圍區(qū)間。
我們通過確定每一個(gè)范圍的頂點(diǎn),來確保獲取到正確的數(shù)據(jù)。這個(gè)時(shí)候我們就需要維護(hù)兩個(gè)有序數(shù)組。
舉例如下:
設(shè)計(jì)一個(gè)系統(tǒng)根據(jù)學(xué)生的成績?yōu)槠浯虻燃壏郑?br>
0~60分[0, 60],等級為D
60~70分(60,70],等級為C
70到80分(70,80],等級為B
80到100分(80,100],等級為A。
var grade = [60, 70, 80, 100];
var rank = [D, C, B, A];
// 按照每一區(qū)間的上線來檢查分?jǐn)?shù)
var maxGradeLelel = grade.length - 1;
var gradeLevel = 0;
var studentGrade = 'A';
while(studentGrade = 'A' && gradeLevel < maxGradeLevel){
if(studentCore < grade[gradeLevel]) {
studentGrade = rank[gradeLevel] ;
break;
}
gradeLevel++;
}