千萬不要把 bool 設計成函數參數

原文地址      http://coolshell.cn/articles/5444.html

作者 陳皓

 

我們有很多Coding Style 或 代碼規範。但這一條可能會經常被我們所遺忘,就是我們經常會在函數的參數裏使用bool參數,這會大大地降低代碼的可讀性。不信?我們先來看看下面的代碼。

當你讀到下面的代碼,你會覺得這個代碼是什麼意思?

 
widget->repaint(false);

是不要repaint嗎?還是別的什麼意思?看了文檔後,我們才知道這個參數是immediate, 也就是說,false代表不立即重畫,true代碼立即重畫。

Windows API中也有這樣一個函數:InvalidateRect,當你看到下面的代碼,你會覺得是什麼意思?

 
InvalidateRect(hwnd, lpRect, false);

我們先不說InvalidateRect這個函數名取得有多糟糕,我們先說一下那個false參數?invalidate意爲“讓XXX無效”,false是什麼意思?雙重否定?是肯定的意思?如果你看到這樣的代碼,你會相當的費解的。於是,你要去看一下文檔,或是InvalidateRect的函數定義,你會看到那個參數是BOOL bErase,意思是,是否要重畫背景。

這樣的事情有很多,再看下面的代碼,想把str中的”%USER%”替換成真實的用戶名:

 
str.replace("%USER%", user,false);  // Qt 3

TNND,那個false是什麼意思?不替換嗎?還是別的什麼意思,看了文檔才知道,false代碼大小寫不敏感的替換。

其實,如果你使用枚舉變量/常量,而不是bool變量,你會讓你的代碼更易讀,如:

 
 
 
 
 
 
widget->repaint(PAINT::immediate);
widget->repaint(PAINT::deffer);
InvalidateRect(hwnd, lpRect,  !RepantBackground);
str.replace("%USER%", user, Qt::CaseInsensitive);// Qt 4

如果對這個事不以爲然的話,我們再來看一些別的示例,你不妨猜猜看看下面的代碼:

 
component.setCentered(true,false);

這什麼玩意兒啊?看了文檔你才知道,這原來是 setCentered(centered, autoUpdate);

 
new Textbox(300, 100, false,true);

這又是什麼啊?看了文檔才知道,這是創建一個文本框,第三個參數是是否要滾動條,第四個是是否要自動換行。TNND。

上面的情況還不算最差,看看下面的雙重否定。

 
 
component.setDisabled(false);
filter.setCaseInsensitive(false)

再來一個,如果你讀到下面的代碼,相信你會和我一樣,要麼石化了,要麼凌亂了。

 
 
event.initKeyEvent("keypress",true,true, null, null,
                   false,false, false,false, 9, 0);

看完這篇文章,我希望你再也不要把bool爲作爲函數參數了。除非兩個原因:

  1. 你100%確認不會帶來閱讀上的問題,比如Java的 setVisible (bool).
  2. 你100%確認你想去寫出無法維護很難閱讀的代碼

【更新2011/9/8】當然,別的參數也會有一樣的問題,比如:new Textbox(300, 100, false, true);中的300 和 100,不知道是座標還是長寬,只不過,一般長度或座標這樣的參數都不會被hard code,都會有變量名,而bool這種參數經常性地被傳成true 和 false。 bool參數表現得更爲明顯一些罷了。

所以,程序中不要出現magic number,true/false 也是一種 magic number。但是,我想告訴大家,從API設計的角度來說,你無法強制調用者用常量來取代true/false,定義成枚舉類型是最好的選擇

最後,如果你想設計一個好的API,強烈推薦你讀一下Nokia的Qt的《API Design Principles》,本文就是其中的“Boolean Trap”。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章