重構(Refactoring)技巧讀書筆記 之三<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
General Refactoring Tips, Part 3
動了情的至尊寶在那個月圓之夜有感而發:長夜漫漫,無心睡眠。從此,他的夜生活變得多姿多彩起來。唉,我以為只有至尊寶才有這等幸運。
想起放在抽屜的《重構》,遂拜讀大師的作品來催眠,度過一個無心睡眠的漫漫長夜。
……
本文繼續重構(Refactoring)技巧讀書筆記系列。重構雖然是對現有的程式碼進行設計,以提高程式碼的質量和靈活性,但實際上,如果軟體工程師掌握重構技術,對其初期的軟體設計也有很好的指導,減少不當設計或設計不足,減少程式碼壞味道(Bad Smell in Codes),構建良好的系統。
注:本文重構策略的名稱及其大部分內容來自《重構-改善既有程式碼的設計》一書,Martin Fowler 著,侯捷等譯。
一、程式碼壞味道(Bad Smell in Codes)及其重構策略
11.Parallel Inheritance Hierarchies(平行繼承體系)
現象:為某個class增加一個subclass時,也必須為另一個class相應增加一個subclass。重構策略: 在一個class繼承體系的物件中引用(refer to)另一個class繼承體系的物件,然後運用Move Method和Move Field將被引用class中的一些方法和成員變數遷移宿主class中,消除被引用class的繼承體系(注:這種平行繼承體系好象比較少見也)。
12.Lazy Class(冗贅類)
現象:某一些class由於種種原因,現在已經不再承擔足夠責任,有些多餘了。如同國有企業冗餘人員一樣,需要下崗了。
重構策略:通過Collapse Hierarchy,將這些冗餘的class合併到superclass或subclass中,或者通過Inline Class(與Extract Class相反),將這些冗餘class中的所有Method/Field遷移到其他相關的class中。
13.Speculative Generality(誇誇其談未來性)
現象:系統中出現一些無用的abstract class,或者非必要的delegation(委託),或者多餘的引數等等。
重構策略:分別使用Collapse Hierarchy合併abstract class,使用Inline Class移除非必要的delegation,使用Remove Parameter刪除多餘的引數。
14.Temporary Field(令人迷惑的暫時值域)
現象:class中存在一些Field,這些Field只在某種非常特定的情況下需要。
重構策略:通過Extract Class將這些孤獨的Field及其相關的Method移植的一些新的Class中。提煉出來的新Class可能沒有任何抽象意義,只是提供Method的呼叫,這些新Class一般稱為Method Object。
15.Message Chains(過度耦合的訊息鏈)
現象:向一個物件請求另一個物件,然後再向後者請求另一個物件,……,這就是Message Chain,意味著Message Chain中任何改變,將導致Client端不得不修改。
重構策略:通過Hide Delegate(隱藏委託關係)消除Message Chain,具體做法是在Message Chain的任何地方通過Extract Method建立一個簡單委託(Delegation)函式,來減少耦合(Coupling)。
16.Middle Man(中間轉手人)
現象:過度運用delegation,某個/某些Class介面有一半的函式都委託給其他class,這樣就是過度delegation。
重構策略:運用Remove Middle Man,移除簡單的委託動作(也就是移除委託函式),讓client直接呼叫delegate受託物件。和上面的Hide Delegate(隱藏委託關係)剛好相反的過程。
由於系統在不斷的變化和調整,因此[合適的隱藏程度]這個尺度也在相應的變化,Hide Delegate和Remove Middle Man重構策略可以系統適應這種變化。
另外,可保留一部分委託關係(delegation),同時也讓Client也直接使用delegate受託物件。
17.Inappropriate Intimacy(狎暱關係)
現象:兩個Class過分親密,彼此總是希望瞭解對方的private成分。
重構策略:可以採用Move Method和Move Field來幫助他們劃清界限,減少他們之間親密行為。或者運用Change Bidirectional Association to Unidirectional,將雙向關聯改為單向,降低Class之間過多的依存性(inter-dependencies)。或者通過Extract Class將兩個Class之間的共同點移植到一個新的Class中。
18.Alternative Classes with Different Interfaces(異曲同工的類)
現象:兩個函式做相同的事情,卻有不同的signature。
重構策略:使用Rename Method,根據他們的用途來重新命名。另外,可以適當運用Move Method遷移某些行為,使Classes的介面保持一致。
19.Incomplete Library Class(不完美的程式庫類)
現象:Library Class(類庫)設計不是很完美,我們需要新增額外的方法。
重構策略:如果可以修改Library Class的Source Code,直接修改最好。如果無法直接修改Library Class,並且只想修改Library Class內的一兩個函式,可以採用Introduce Foreign Method策略:在Client Class中建立一個函式,以外加函式的方式來實現一項新功能(一般而言,以server class例項作為該函式的第一個引數)。
如果需要建立大量的額外函式,可應該採用Introduce Local Extension:建立一個新class,使它包含額外函式,並且這個class或者繼承或者wrap(包裝)source class。
20.Data Class(純稚的資料類)
現象:Data Class指:一些Class擁有Fields,以及用來訪問Fields的getter/setter函式,但是沒有其他的功能函式。(感覺這些Data Class如同Entity Class或Parameter Class,用來傳遞引數,我認為這種情況下沒有必要重構。)
重構策略:找出其他class中訪問Data Class中的getter/setter的函式,嘗試以Move Method將這些函式移植到Data Class中,實現將資料和操作行為(方法)包裝在一起,也讓Data Class承擔一定的責任(方法)。
21.Refused Bequest(被拒絕的遺贈)
現象:Subclass不想或不需要繼承superclass的部分函式和Field。
重構策略:為subclass新建一個兄弟(sibling class),再運用Push Down Method和Push Down Field將superclass中的相應函式和Field下推到兄弟class,這樣superclass就只包含subclass共享的東西了。其實,也就是將superclass中一些與特定的函式和Field放到特定的subclass中,superclass中僅包含subclass共享的函式和Field。
如果不想修改superclass,還可以運用Replace Inheritance with Delegation來達到目的。也就是以委託取代繼承,在subclass中新建一個Field來儲存superclass物件,去除subclass對superclass的繼承關係,委託或呼叫superclass的方法來完成目的。
22.Comments(過多的註釋)
現象:(暈倒,這個也要重構,Remove掉所有的Comments嗎?不是。)當程式碼中出現一段長長的註釋,一般是由於程式碼比較糟糕,需要進行重構,除去程式碼的壞味道。
重構策略:通過上面提及的各種重構策略,將程式碼的壞味道去除,使註釋變成多餘。
如果需要註釋/解釋一段程式碼做了什麼,則可以試試Extract Method,提取出一個獨立的函式,讓函式名稱解釋該函式的用途/功能。另外,如果覺得需要註釋來說明系統的某些假設條件,
也可嘗試使用Introduce Assertion(引入斷言),來明確標明這些假設。
當你感覺需要撰寫註釋時,請先嚐試重構,試著讓所有的註釋都變得多餘。
程式碼的壞味道(Bad Smell in Codes)學習完了,走完了第一步。後面的內容也翻過多次,感覺還是蠻好懂的。嗯,今天掌握了挑別人程式碼毛病的精銳武器。鬱悶的是,自己寫的程式碼也需要重構。
References:
1, Rickie, 重構(Refactoring)技巧讀書筆記 之一
2, Rickie, 重構(Refactoring)技巧讀書筆記 之二