2 Long Method (過長函數(shù))
擁有短函數(shù)的對象會活的比較好,比較長. 不熟悉面向對象的人,常常覺得對象程序中只有無窮無盡的委托,根本沒有進行任何計算. 和此類程序共同生活數(shù)年之后,你才會知道, 這些小小函數(shù)有多大價值. "間接層"所能帶來的全部利益- 解釋能力,共享能力,選擇能力.這都是由小型函數(shù)支持的.
很久以前程序員就已經(jīng)認識到: 程序越長越難理解. 早期的程序語言中, 子程序調用需要額外的開銷, 這使得人們不太樂意使用小函數(shù). 現(xiàn)代OO語言幾乎已經(jīng)完全免除了進程內調用開銷. 不過代碼閱讀者還是得多費力氣. 因為他必須常轉換上下文去看看子程序做了什么. 某些開發(fā)環(huán)境允許用戶同時看到兩個函數(shù). 這可以幫助你省去部分麻煩. 但是讓小函數(shù)容易理解的真正關鍵在于一個好名字. 如果你能給函數(shù)起個好名字. 讀者就可以通過名字了解函數(shù)的作用了, 根本不必去看其中寫了些什么.
最終的結果是: 你應該更積極地分解函數(shù). 我們遵循這樣一個原則: 每當感覺需要以注釋說明點什么的時候. 我們就把需要說明的東西寫進一個獨立的函數(shù)中, 并以其用途(而非實現(xiàn)手法)命名. 我們可以對一組甚至短短一行代碼做這件事.哪怕替換后的函數(shù)調用動作比函數(shù)自身還長, 只要函數(shù)名稱能夠解釋其用途, 我們也該毫不猶豫地那么做. 關鍵不在于函數(shù)的長度, 而在于函數(shù)"做什么" 和 "如何做" 之間的語意距離.
99%的場合中, 要把函數(shù)變小, 需要使用 Extract Method(提煉函數(shù)), 找到函數(shù)中適合集中在一起的部分, 將他們提煉出來形成一個新函數(shù).
如果函數(shù)內有大量的參數(shù)和臨時變量, 他們會對你的函數(shù)提煉形成阻礙. 如果你嘗試使用Extract Mothod(提煉函數(shù)), 最終就會把許多參數(shù)和臨時變量當作參數(shù), 傳遞給被提煉出來的新函數(shù), 導致可讀性幾乎沒有任何提升. 此時, 你可以經(jīng)常運用Replace Temp With Query(以查詢取代臨時變量)[這個方法往往是你運用Extract Method之前比不可少的一個步驟] 來消除這些臨時元素. Introduce Parameter Object(引入?yún)?shù)對象) 和 Preserve Whole Object(保持對象完整)則可以講過長的參數(shù)列變得更簡潔一些.
如果你已經(jīng)這么做了, 仍然有太多臨時變量和參數(shù), 那就應該使出我們的殺手锏: Replace Method With Method Object(以函數(shù)對象取代函數(shù)).
如何確定該提煉那一段代碼呢? 一個很好的技巧是: 尋找注釋. 他們通常能指出代碼用途和實現(xiàn)手法之間的語義距離. 如果代碼前方有一行注釋, 就是提醒你: 可以講這段代碼替換成一個函數(shù), 而且可以在注釋的基礎上給這個函數(shù)命名. 就算只有一行代碼, 如果它需要以注釋來說明. 那也值得將它提煉到獨立函數(shù)去.
條件表達式和循環(huán)常常也是提煉的信號. 你可以使用Decompose Conditional(分解條件表達式) 處理條件表達式. 至于循環(huán), 你應該講循環(huán)和其內的代碼提煉到一個獨立函數(shù)中.