豆知識是指各種很瑣碎、不成系統、缺乏邏輯連貫性的零碎條目知識。
像「隨便在自己啟動的Thread中更新UI內容會導致AndroidAPP當機喔!」這就是種豆知識。
那...豆技巧呢?
最知名的豆技巧:請計算連續數字M~N的總和。
菜鳥會乖乖用矩陣計算答案,(如果這是場考試,這題就會拿零分。)
int sum = 0
for(int i = M ; i <= N ;i++){
sum += i;
}
但正確答案是用梯形面積的數學公式去計算。
int sum = (M + N)(N - M)/2;
明明需要計算「連續數字M~N的總和」的情境,在現實中幾乎是可遇不可求,但某些(還算常見的)程式設計教育(藉由這種考題)會讓工程師以為「正確使用矩陣、習慣使用矩陣、堅定使用矩陣,是徒勞無益且多餘的行為。」
一件很明確的事情有個很明確的答案,這個答案就是豆技巧。既然都是種「豆」,豆技巧一樣也是各種很瑣碎、不成系統、缺乏邏輯連貫性的零碎條目程序。
一個物件的「建構式」是種豆知識,但很多物件的「建構式」擺在一起卻可能有種「系統」與「邏輯連貫性」。用建構式做例子會有點狹隘,在禮拜五的晚上,我一時也想不到(也沒那個力氣尋找)更好的例子了。
但有些豆技巧還真的挺重要,而且變化起來很方便,就不會「只能用在考試中」。
像「把十進位轉換成十六進位」。
String hex(int n){
String hexString = "0123456789ABCDEF";
return hextString.getCharAt(n);
}
上面這個函數還需要補足一些「大於16」的邏輯判斷和遞迴應用。
hexString其實就是個「0~F」的字元符號矩陣,字元在矩陣中的位置剛好對應了「0~15」。
如果可以從中看出「不需要判斷」「直接用參數決定要取用哪些東西」的設計概念,那可以應用在很多地方。
像下面這樣的例子...
void test(int index){
if(index == 0){
...
}
else if(index == 1){
...
}
else if(index == 2){
...
}
}
範例中已經很「體貼」的使用了0/1/2...作為index的判斷值,但現實中這樣寫程式是作死!
首先,為了方便使用這個test函數,(假設它是個library/module,寫它的人未必是用它的人,)就需要讓使用者知道可以傳入哪些數值,所以會有一排精準定義過名稱(看了就知道幹嘛)的參數在物件中。
例如.......
final int Test_Index_0 = 0;
final int Test_Index_1 = 1;
final int Test_Index_2 = 2;
這樣,使用者就知道可以帶這些參數進test中。(名字當然可以取的更好懂,例如直接表達這個參數的目的,例如「Test_Index_Init」「Test_Index_Loop」這種形式。)
接著,這樣寫出來的程式很冗長,很難擴充跟維護。
像「如果要新增幾個Test_Index_3/Test_Index_4/Test_Index_6(跳過Test_Index_5)
」呢?
將if..else改成switch?這野心太小。
首先要擴充參數...
final int Test_Index_0 = 0;
final int Test_Index_1 = 1;
final int Test_Index_2 = 2;
final int Test_Index_3 = 3;
final int Test_Index_4 = 4;
final int Test_Index_6 = 6;
我們導入設計模式中的策略模式吧!先定義一個策略模式...
interface TestFunction{
void func(int v);
}
class Test0 implements TestFunction{...}
class Test1 implements TestFunction{...}
class Test2 implements TestFunction{...}
class Test3 implements TestFunction{...}
class Test4 implements TestFunction{...}
class Test6 implements TestFunction{...}
然後來重新修改剛剛的test函數...
TestFunction[] funcs = {
new Test0(), new Test1(), new Test2(), new Test3(), new Test4(), null, new Test6()
}
void test(int index, int v){
if(funcs[index] != null)
funcs[index].func(v);
}
這樣,程式就會變得很好擴充。未來即使要再新增更多對應功能,也只需要將新功能用物件實作後,在funcs中新增該物件的實體即可讓新功能被test函數使用。
(看過專案起始的工程師不懂這個技巧,就只使用switch,然後接手的工程師就把擴充維護給搞砸搞爛了......)