代碼的壞味道 一、Duplicate Code 1、同一個類,兩個方法含有相同表達式。 解決方法:你可以Extract Method提煉重復代碼,然後讓這兩個方法都調用這個Extract Method。 2、兩個類,有相似的方法。 解決方法:(1)把兩個類的方法提出來,共同構造一個父類。 (2)把其中一個類的方法刪除,調用另一個類的方法。 二、Long Method 1、短函數:代碼閱讀費點力氣,因為我們必須經常轉換上下文去看看子程序做了什麼。但是讓small method容易理解的真正關鍵在於一個好的名字。讀者可以通過名字了解函數的作用,根本不必去看其中寫了些什麼。——早期的編程語言中,調用方法需要額外開銷,這使得coder不願意使用small method。但是現代的OO語言幾乎已經完全免除了process內的額外開銷(函數調用)。 2、注釋地方提煉信號:每當感覺需要以注釋來說明點什麼的時候,我們就把需要說明的東西寫進一個獨立函數中,並以其用途命名。可以對一組或甚至短短一行代碼做這件事。——只要函數名稱能夠解釋其用戶,我們也該毫不猶豫地那麼做。 "函數"理解為”做什麼“或”如何做“ 3、條件式和循環常常也是提煉信號。 4、《代碼整潔之道》的一個例子。我們可以想想! 三、Large Class 1、Class內數個屬性變量有相同前綴或者字尾,可使用Extract Class。 2、Class內並非大多數變量使用屬性變量,可使用Extract Class。 3、有太多代碼,可Extract Class。 四、Long Parameter 做成Introduce Parameter Object。——這個我不太贊同,因為我在使用別人方法的時候,我很少去看代碼實踐,更不要說去看裡面都用到了對象的那些屬性或者方法,取我想要的數據了。 五、Switch Statements 1、少用switch語句。——問題在於duplication。添加新case的時候,你必須找到所有case並修改它們。 2、用多態來替換它。做法:1.將switch進行Extract Method;2.MoveMethod把case裡的實踐代碼放到多態性的class裡。 六、 Comments 試試用Extract Method,如果還不行,那你試試Rename Method。 當你感覺需要撰寫注釋,請先嘗試重構,試著讓所有注釋變得多余。 注釋一般用於將來的打算,還可以用於你並無十足把握的區域(為什麼做某事)。
動機:
簡短而有良好命名的函數:——finely grained
1、復用機會大。
2、函數讀起來像讀一系列comments。
3、函數覆寫容易。
重點:函數長度關鍵在於函數名稱和函數本體之間的語義距離。如果提煉動作可以強化代碼的清晰度,那麼就去做。
作法:
1、創建新函數,根據函數的意圖命名——以它“做什麼”命名,而不是以它“怎樣做”命名。
=》 即使Extract Function 非常簡單,例如只是消息或函數調用,只要新Function能夠以更好方式昭示代碼意圖,你也應該提煉它。但如果你想不出更有意義的名稱,就別動它。
2、將Extract的代碼從Source Function 中Move到New Function中。
二、Inline Method
Method Body與Method Name一樣清晰易懂的時候,請Inline Method。
三、Inline Temp
一個臨時變量,只被一個簡單表達式賦值一次,而且賦值完也只使用了一次。——請Inline Temp
四、Replace Temp with Query
如果一個Temp變量,保存一個表達式,將這個表達式Extract Method。——這就是所謂的查詢式,query
動機:
1、局部變量會使代碼難以提煉。
2、臨時變量會驅使你寫出更長的代碼。如果改成query method,那麼class下的method,都可以獲得這份信息。——將編寫出更清晰的代碼。
3、Replace Temp with Query往往是你運用Extract Method之前必不可少的步驟。
作法:
1、找出只被賦值一次的臨時變量。
=> 如果臨時變量賦值超過一次,考慮使用Split Temporary Variable將它分割成多個變量。
2、對Temp Variable賦值的右側部分,Extract到一個獨立函數中。
=> 將Method聲明為private,日後如果有其他class用的時候再放開它(public或protected)。
如果代碼組織良好,那麼你往往能發現更有效的優化方案。————如果性能真的很糟糕,那麼放回去也很容易。 五、Introduce Explaining Variable 將復雜表達式中(或其中一部分)的結果放進一個臨時變量,以此變量名稱來解釋表達式用途。 動機: 表達式復雜而且難以閱讀。在這種情況下,臨時變量可以幫助你將表達式分解為比較容易管理的形式。 六、Split Temporator Variable 某個臨時變量被賦值超過一次,它既不是循環變量,也不是集合變量。那麼針對每次賦值,創造一個獨立的,對應的臨時變量。
動機:
1、如果臨時變量承擔多個責任,它就應該被替換為多個臨時變量。每個變量只承擔一個責任。
2、同一個臨時變量承擔兩件不同的事情,會令review變得糊塗。
六、Remove Assignments To Parameters 如果你的代碼對參數進行賦值,那麼以一個臨時變量取代該參數的位置。
七、Replace Method with Method Object
大型函數對局部變量的使用無法采用Extract Method。那麼將這個Method放進一個單獨對象中,如此一來,讓局部變量成為對象的filed,然後在同一個對象中將大型函數分解為數個小型Method。
動機:
1、將相對獨立的代碼從大型Method中Extract出來,就可以大大提高代碼的可讀性。
2、一個Method中,局部變量泛濫成災,分解這個函數將會非常困難。
3、Replace Method with Method Object 會將所有局部變量變成對象的值域。然後對這個新對象進行Extract Method了。
八、Substitute Algorithm 如果你想把某個算法替換為另一個更清晰的算法,那麼將Method Body替換為另一個算法。——就是直接修改原來的Method Body。 動機:隨著對問題有了更多的了解,你發現一件事可以有更清晰的方式,就應該以較清晰的方式取代復雜方式。 總結 這只是本書的一部分內容,我知道會有很多的coder應該有不同的觀點,我自己也是,有的很贊同,有的我也是不太贊同的。所以要“則其善之而從之,其不善之而改之”。 歡迎大家發表下自己的看法。