iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
Mobile Development

我的怨念齊天高 之「為什麼我的專案死掉了!」系列 第 19

布林值判斷的一些豆技巧(弄不好也是會造成專案死掉的)

  • 分享至 

  • xImage
  •  

前天講了豆技巧,今天再講一點好了...

假設有個情境是要用數個布林值來判斷接下來要做什麼動作,先從簡單的兩個布林值(a, b)開始。

我們會得到四種組合...或說四個「程式碼的分支」。


if(a == true && b == true){...}
else if(a != true && b == true){...}
else if(a == true && b != true){...}
else{...}

同樣的豆技巧一樣可以用在簡化這個情境上...

這個技巧的原理基本上是以二進位計算為基礎,其實一個八位元數字等於八個布林值所組成,以此類推一個十六位元數字等於十六個布林值所組成,一個三十二位元數字等於三十二個布林值所組成。

但先簡單一點,說說看怎麼用在兩個布林值的簡化上。

0等於「所有布林值皆為false」,那1就等於「第一個布林值為true」。

換個比較好懂的寫法...把0跟1轉化成八位元二進位表達。

00000000等於「所有布林值皆為false」,那00000001就等於「第一個布林值為true」。

再來...

那00000010(2)就等於「第二個布林值為true」。
那00000011(1+2)就等於「第一與第二個布林值皆為true」。

把這個概念應用在判斷上,就不需要寫判斷式,改成如下...

首先定義一個接口來實作每個組合要對應的動作。

interface Act{
  void act();
}

然後...

Act[] acts = new Act[4]; //因為有兩個布林值有四種情況

int index = 0;
index += (a)?1:0;
index += (a)?2:0;

acts[index].act();

以此類推,一個index最多可以對應32組布林值判斷。

但其實這種豆技巧反映的是「位元運算」的應用。「位元運算」可以應用的地方還很多,而且不是所有人都喜歡用Strategy模式來解決問題。

更重要的是...會害專案死掉的「布林值判斷」並不在「寫太多」,而在於「寫太雜」。

像下面這種情況一旦發生,後續維護升級擴充就很難成功:

if(a){
  funcA();
  funcB();
  funcD();
}
else{
  funcC();
  funcB();
  funcA();
}

funcA/funB/funC/funcD只是為了方便表達,但如果是尚未集合成函數的散亂程式碼,只是功能相同而已。

這種寫法還可能會有魔改變化形式,如果我們多增加了b和c的布林值...

if(a){
  funcA();
  if(b)
    funcB();
  funcD();
}
else{
  funcC();
  if(b)
    funcB();
  funcA();
}

維護這種程式碼最大的阻礙,首先在於「程式碼又多又長」,所以後續維護的人經常無法看出結構上可以簡單歸類,所以就不知道funcA同時存在於兩個地方,結果修改了其中一處,但另一處卻沒修改到,結果徒增測試所需要耗費的資源。

(這是根本上「不重構」「不優化」造成的結果。但現階段不想討論這個。)

優化、避免這種寫法出現的技巧,其實是類似的。主要就是避免因為使用「if...else」造成「程式碼出現分支」。

先不要使用「Act」這樣的介面,就單純地看一下沒有分支的程式碼長什麼樣...

if(a){  funcA();}
else{  funcC();}

if(b){  funcB();}

if(a){  funcD();}
else{  funcA();}

雖然還是使用了「if...else」,但程式碼被很清楚的區隔開,後續會比較好閱讀,發現funcA段的程式碼重複、可以獨立成一個函數的機會也能高很多。

(雖然這種寫法的好處很明顯,但我也看過有些工程師堅持「這種寫法不直覺」而否定這種寫法。)

比起測試一個工程師是否懂「MVVM在官方網頁的定義」「某某元件在官方API的解釋」,「能理解」或「能使用」這種豆技巧是否更能反映一個工程師的能力?(先不提程式套件的知識,至少在建構程式思維的靈活度上,這些問題更有指標性才對。)


上一篇
恐怖的全端工程師
下一篇
失敗的升級維護...
系列文
我的怨念齊天高 之「為什麼我的專案死掉了!」20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言