天天看點

寫給自己看的小設計2 - 對象設計通用原則(序)

代碼就應該簡單,短小,易懂。

  程式設計技術發展至今,對象的概念始終貫穿與設計過程的始終,廣義的對象包括了參與設計的所有程式設計元素,比如變量,函數,類,元件,服務等。在程式設計理論中,對象的設計基本上就等同于設計的全部。在對象設計的進化過程中,漸漸的就有了一些通用的規則。人們常說美食要色香味俱全,代碼也不例外,這裡首先總結了設計中最重要,也最容易為人所忽略的幾個原則,這幾個點都是描述代碼的外觀特點,我稱之為"代碼之形",我認為它們是一切設計的起點和基礎。

代碼之"形"

  我記得一位牛叉的程式員說過:任何程式員都能寫出機器能懂的代碼,隻有最優秀的程式員才能寫出人能懂的代碼。人能懂的代碼最基本的要滿足下面的幾個條件。

1. 簡單

  這一原則非常簡單,又非常重用,任何難以維護和擴充的代碼基本都不是簡單的代碼,靈活開發提倡簡單設計,我個人覺得還是非常有道理的,越是簡單的設計,越是簡單的代碼,越是容易維護,越是容易重構,問題也相對越少。

  當然了,簡單并不等同于代碼越少越好,功能越少越好,這裡的簡單通常指的是邏輯處理上應用簡單直接的設計來滿足目前的需求。

  在重構理論中,也非常強調邏輯簡單,比如少用複雜的運算符和複雜的邏輯條件,每個循環争取隻幹一件事等等。

  在程式設計理論中有一個很重要的概念叫做圈複雜度,它是用來衡量函數的複雜性的。

  函數圈複雜度計算的方法很簡單:

 

每個函數圈複雜度起始值為1,代表有一個路徑執行完函數,每遇到一個if/case/for/while/and(邏輯與運算,如&&)/or(邏輯或運算,如||)就增加1,這樣計算的最終結果就是函數的圈複雜度。      

  圈複雜度越大,說明函數越複雜,越有存在缺陷的可能,也越有重構的必要。

  個人認為把函數的圈複雜度控制在10以内是比較好的做法。

  對于對象的設計,有一種觀點我覺得很對,那就是:如非必要,請遠離各種設計模式。這個觀點的就如同另外一個觀點一樣智慧:如非必要,請不要試圖優化代碼,提高效率。

  我記得曾有位仁兄使用了23中設計模式實作了不同的"Hello World",從學習角度,我還是很佩服其想象力的;但是從實用角度,我隻能表示"呵呵"了。

2. 大小合适

  代碼邏輯簡單的一個很重要的衍生規則就是代碼數量要大小适中。我很難想像任何人看見内容有1000行代碼的函數和内容隻有10行代碼的函數感覺會是一樣!小通常意味着簡單。反之也成立。個人認為把函數的行數限制在50行以内,類的方法限制在30以内是很好的做法。超過這個數目,就有了重構的必要。

  有一種很有市場的觀點就是:如果小函數很多的話,調用堆棧就會很長,這樣執行的效率就不會高。

  針對這種觀點,我的想法是:且不說現在硬體的性能每年都在進行着翻天覆地的變化,就說現在的編譯器已經足夠智能了,小函數大多數情況下都在編譯時内聯了,執行的效率損失幾乎是微乎其微。而且從我的感覺來看,大部分項目失敗的原因中,除了對效率要求特别高的項目(我們大部分項目都不屬于這一類),因為效率原因失敗的是少之又少。

  另一種觀點是:控制函數行數的話,意味着要拆分很多的小函數,小函數很多了也不好管理,于是不要拆分了。

  确實,這個問題是真實存在的問題,每個人可能都會遇到,但是我覺得通過使用注釋标記(特别是C#中有region)還是可以很好管理的。而且相對于小函數帶來的可讀性和易維護,這點損失還是值得的。

  是以,我的觀點是盡情通過重構去控制函數的大小吧,無需多慮(我還真怕有人跟我擡杠說:"那你怎麼不一句話一個函數呢?")。

3. 命名易懂

  這條原則無論如何強調都不為過,原因你懂的。對象命名的好壞程度直接反應了一個碼農程式設計水準的高低程度,對我來說,命名是任何一個人的基本功,可不僅僅是程式員的基本功。

  我記的一個牛叉的程式員曾經說過,好的程式,每個變量,函數,類的名字都非常講究,整體搭配的也都非常合适,閱讀這樣的程式,就像閱讀一篇優美的散文一樣,讓人賞心悅目。

  我想任何人都到下面兩種代碼的感覺都不一樣:

// Bad
var s = "Frank";
 
// Good
var usr_name = "Frank";
// or
var usrName = "Frank";      

  上面不推薦的那種寫法對于for循環中的循環變量int i來說問題還好,大家已經約定俗成了。如果放到一般的變量上,這種做法就不是太好了。

  當然了這種代碼通常不是一次寫就的,優秀的程式員開始寫的程式也都可能像狗屎一樣,不過他們高人一籌的地方就在于代碼能工作之後,他們不會停下來,而是不斷的打磨自己的代碼,讓它們簡單,易懂,靈活。

繼續閱讀