程式碼潔癖系列(三):整潔的類和函數
- 2020 年 3 月 11 日
- 筆記
前面我們討論了什麼樣的命名更能夠讓你賞心悅目,今天來討論一下面向對象編程過程中最重要的環節,編寫類和函數。我們仍然用Java來演示,什麼樣的類和函數才算是整潔的。
首先討論函數,函數定義好了,類也就容易了。
短小
相信大家在讀程式碼的時候都會遇到過冗長的函數定義。沒有的話可以私信我,我把原來寫過的一段300+行的函數發給你,不過不要問我這個函數是做什麼的,因為我也忘了,而且不想回顧。當然如果你足夠耐心研究出來了,請教教我。
言歸正傳,為什麼函數要短小呢,如何才能是自己的函數更加短小?第一個問題我也無法證明,只能告訴你短小的函數看起來更加清晰,更加容易理解。那怎麼才能讓函數變得更加短小呢?很簡單,抽離方法。將一些程式碼抽離成另一個函數。什麼樣的長度才是合適的呢?我認為不必過於追求短。這裡的長度我們可以以程式碼塊的層來定義,對於下面這種程式碼相信任何人看了都會崩潰吧。
public void doSomething() { for() { ... while() { ... if() { ... }else { ... } } } }
所以每個函數中有一層或兩層為最佳,每層程式碼塊最好不超過3行。這是我認為最佳的函數長度,當然,這個也可以根據個人習慣稍作調整。
只做一件事
如果說長度還可以根據個人習慣,那麼「只做一件事」的要求應該是大家都應該遵守的公約了。如果一個函數中做了太多的事,那麼程式碼閱讀起來的難度將會成倍增加,而且文檔書寫難度同樣增大。還有就是給其他程式碼調用造成不便。比如我定義了函數A做了1和2兩件事,函數B想做2和3,怎麼辦?這時B只能再寫一遍A中做2的程式碼。而這樣就會有大量重複程式碼出現,不但增加工作量,對日後的維護工作也造成很大的負擔。而把1和2分別定義為函數C和函數D的話,只需要在AB中分別調用就可以了。
命名
這裡不多解釋,函數的命名需要具有描述意義,函數越短也就越容易描述。
函數參數
參數數量越少越好(這個我目前也沒有做到),究其原因,首先是讀程式碼時每次都要搞清楚每個參數的意義,所以自然越少越好。另一方面就是為測試的同事提供方便,如果有多個函數,測試的同學就需要考慮更多的測試用例對其進行覆蓋。如果一個函數有3個以上的參數,那測試的同學可能想要打人了。
使用異常代替返回錯誤碼
這樣就可以將Try/catch程式碼塊抽離出來,因為Try/catch程式碼塊影響了正常程式的流程,看起來很醜陋。
函數的主要規則就是這些,那麼如何才能寫出這樣的函數呢?其實沒有什麼特別的技巧,就是記住這些規則,在每次寫完程式碼之後再斟酌一番,對程式碼進行反覆的打磨,修改不合適的命名,抽離冗長的函數。久而久之,你的程式碼一定會被人稱讚的。
說完函數再來說一下如何寫好一個類。
還是短小
沒錯,類也應該短小,不過這裡短小的定義和函數短小的定義稍有不同,我們通常以「權責」來衡量。先看下面這個類。
public class SuperDashboard extends JFrame implements MetaDataUser { public Component getLastFocusedComponent() public void setLastFocused(Component lastFocused) public int getMajorVersionNumber() public int getMinorVersionNumber() public int getBuildNumber() }
這個類只提供了5個方法,應該不算長,但是我要說,它仍然不滿足我們「短小」的條件,原因就是違反了單一權責原則。單一權責指的是一個類只描述一類事。上面這個類有對最後焦點組件的讀寫方法,還有獲取版本號和序列號的方法。只要我們描述一個類時,用到了類似於「還有」這樣的字眼時,那麼這個類就違反了單一權責原則,就需要對其中的方法進行抽離。
為了修改而組織
大多數系統都會進行持續的迭代,而這也意味著我們需要不斷對程式碼進行修改。而修改程式碼往往伴隨著風險。所以,我們需要做的就是,修改一個方法時,不對其他方法造成影響。當我們開始修改時,就要評估好影響,然後將方法進行抽象,拆分。力求做到每次修改都不影響其他類(即降低耦合)。
對於寫好一個類,總結來說就是「高內聚,低耦合」。想要寫好一個類同樣需要反覆琢磨。沒有人一開始就能寫出很優雅的程式碼。最後祝點贊的人寫的程式碼越來越優雅把。

—END—