### 重構的記錄格式
介紹重構時,我采用一種標準格式。每個重構手法都有如下五個部分:
- 首先是名稱(name)。建造一個重構詞匯表,名稱是很重要的。這個名稱也就是我將在本書其他地方使用的名稱。
- 名稱之后是一個簡短概要。(summary),簡單介紹此一重構手法的適用情景,以及它所做的事情。這部分可以幫助你更快找到你所需要的重構手法。
- 動機(motivation),為你介紹「為什么需要這個重構』和「什么情況下不該使用這個重構」。
- 作法(mechanics),簡明扼要地一步一步介紹如何進行此一重構。
- 范例(examples),以一個十分簡單的例子說明此重構手法如何運作。
「概要」(summary)包括三個部分:(1)一個簡短文句,介紹這個重構能夠幫助的問題;(2)一段簡短陳述,介紹你應該做的事;(3)一幅速寫圖,簡單展現重構前后示例;有時候我展示代碼,有時候我展示統一建模語言(UML)圖。哪一種形式能更好呈現該重構的本質,我就使用該種形式(本書所有UML圖都根據實現觀點(implementation perspective)而畫[Fowler,UML]。〕如果你以前見過這一重構手法,那么速寫圖能夠讓你迅速了解這一重構的概況;如果你不曾見過這個重構,可能就需要瀏覽整個范例,才能得到較好的認識。
「作法」(mechanics)出自我自己的筆記。這些筆記是為了讓我在一段時間不做某項重構之后還能記得怎么做。它們也頗為簡潔,通常不會解釋「為什么要這么做那么做」。我會在「范例」(examples)給出更多解釋。這么一來「作法」就成了簡短的筆記。如果你知道該使用哪個重構,但記不清具體步驟,可以參考「作法」部分(至少我是這么使用它們的);如果你初次使用某個重構,可能「作法」對你還不夠,你還需要閱讀「范例」。
撰寫「作法」的時候,我盡量將重構的每個步驟都寫得簡短。我強調安全的重構方式,所以應該采用非常小的步驟,并且在每個步驟之后進行測試。真正工作時我通常會采用比這里介紹的「嬰兒學步」稍大些的步驟,然而一旦遇上臭蟲,我就會撤銷上一步,換用比較小的步驟。這些步驟還包含一些特定狀況的參考,所以它們也有檢驗表(checklist)的作用;我自己經常忘掉這些該做的事情。
「范例」(examples)像是簡單而有趣的教科書。我使用這些范例是為了幫助解釋重構的基本要素,最大限度地避免其他枝節,所以我希望你能原諒其中的簡化工作(它們當然不是優秀商用對象設計的適當例子)。不過我敢肯定你一定能在你手上那些更復雜的情況中使用它們。某些十分簡單的重構干脆沒有范例,因為我覺得為它們加上一個范例不會有多大意義。
更明確地說,加上「范例」僅僅是為了闡釋當時討論的重構手法。通常那些代碼最終仍有其他問題,但修正那些問題需要用到其他重構手法。某些情況下數個重構經常被一并運用,這時候我會把某個范例拿到另一個重構中繼續使用。大部分時候,一個范例只為一項重構而設計,這么做是為了讓每一項重構手法自給自足(self-contained),因為這份重構名錄的首要目的還是作為參考工具。
這些例子不會告訴你「如何設計一個"employee"對象或一個"order"對象」。這些例子的存在純粹只是為了說明重構,除此之外別無用途。例如你會發現,我在這些例子中用double數據來表示貨幣金額。我之所以這樣做,只是為了讓例子簡單一些,因為「以什么形式表示金額」對于重構自身并不重要。在真正的商用軟件中,我強烈建議你不要以double表現金額。如果真要表示貨幣金額,我會使用Quantity模式[Fowler,AP]。
撰寫本書之際,商業開發中使用得最多的是Java1.1,所以我的大多數例子也以Java1.1寫就,這從我對群集(collections)的使用就可以明顯看出來。本書即將完成之時,Java2己經正式發布。但我不覺得有必要修改所有這些例子,因為對重構來說,群集(collections)也是次要的。但是有些重構手法,例如Encapsulate Collection,在Java1.2中有所不同。這時候我會同時解釋Java2和Java1.1。
修改后的代碼可能被埋沒在未修改的代碼中,難以一眼看出,所以我使用粗體(boldface code)突顯修改過的代碼。但我并沒有對所有修改過的代碼都使用粗體字,因為一旦修改過的代碼太多,全都粗體反而不能突顯重點。
- 譯序 by 侯捷
- 譯序 by 熊節
- 序言
- 前言
- 章節一 重構,第一個案例
- 起點
- 重構的第一步
- 分解并重組statement()
- 運用多態(Polymorphism)取代與價格相關的條件邏輯
- 結語
- 章節二 重構原則
- 何謂重構
- 為何重構
- 「重構」助你找到臭蟲(bugs)
- 何時重構
- 怎么對經理說?
- 重構的難題
- 重構與設計
- 重構與性能(Performance)
- 重構起源何處?
- 章節三 代碼的壞味道
- Duplicated Code(重復的代碼)
- Long Method(過長函數)
- Large Class(過大類)
- Long Parameter List(過長參數列)
- Divergent Change(發散式變化)
- Shotgun Surgery(散彈式修改)
- Feature Envy(依戀情結)
- Data Clumps(數據泥團)
- Primitive Obsession(基本型別偏執)
- Switch Statements(switch驚悚現身)
- Parallel Inheritance Hierarchies(平行繼承體系)
- Lazy Class(冗贅類)
- Speculative Generality(夸夸其談未來性)
- Temporary Field(令人迷惑的暫時值域)
- Message Chains(過度耦合的消息鏈)
- Middle Man(中間轉手人)
- Inappropriate Intimacy(狎昵關系)
- Alternative Classes with Different Interfaces(異曲同工的類)
- Incomplete Library Class(不完美的程序庫類)
- Data Class(純稚的數據類)
- Refused Bequest(被拒絕的遺贈)
- Comments(過多的注釋)
- 章節四 構筑測試體系
- 自我測試代碼的價值
- JUnit測試框架
- 添加更多測試
- 章節五 重構名錄
- 重構的記錄格式
- 尋找引用點
- 這些重構準則有多成熟
- 章節六 重新組織你的函數
- Extract Method(提煉函數)
- Inline Method(將函數內聯化)
- Inline Temp(將臨時變量內聯化)
- Replace Temp with Query(以查詢取代臨時變量)
- Introduce Explaining Variable(引入解釋性變量)
- Split Temporary Variable(剖解臨時變量)
- Remove Assignments to Parameters(移除對參數的賦值動作)
- Replace Method with Method Object(以函數對象取代函數)
- Substitute Algorithm(替換你的算法)
- 章節七 在對象之間搬移特性
- Move Method(搬移函數)
- Move Field(搬移值域)
- Extract Class(提煉類)
- Inline Class(將類內聯化)
- Hide Delegate(隱藏「委托關系」)
- Remove Middle Man(移除中間人)
- Introduce Foreign Method(引入外加函數)
- Introduce Local Extension(引入本地擴展)
- 章節八 重新組織數據
- Self Encapsulate Field(自封裝值域)
- Replace Data Value with Object(以對象取代數據值)
- Change Value to Reference(將實值對象改為引用對象)
- Replace Array with Object(以對象取代數組)
- Replace Array with Object(以對象取代數組)
- Duplicate Observed Data(復制「被監視數據」)
- Change Unidirectional Association to Bidirectional(將單向關聯改為雙向)
- Change Bidirectional Association to Unidirectional(將雙向關聯改為單向)
- Replace Magic Number with Symbolic Constant(以符號常量/字面常量取代魔法數)
- Encapsulate Field(封裝值域)
- Encapsulate Collection(封裝群集)
- Replace Record with Data Class(以數據類取代記錄)
- Replace Type Code with Class(以類取代型別碼)
- Replace Type Code with Subclasses(以子類取代型別碼)
- Replace Type Code with State/Strategy(以State/strategy 取代型別碼)
- Replace Subclass with Fields(以值域取代子類)
- 章節九 簡化條件表達式
- Decompose Conditional(分解條件式)
- Consolidate Conditional Expression(合并條件式)
- Consolidate Duplicate Conditional Fragments(合并重復的條件片段)
- Remove Control Flag(移除控制標記)
- Replace Nested Conditional with Guard Clauses(以衛語句取代嵌套條件式)
- Replace Conditional with Polymorphism(以多態取代條件式)
- Introduce Null Object(引入Null 對象)
- Introduce Assertion(引入斷言)
- 章節十一 處理概括關系
- Pull Up Field(值域上移)
- Pull Up Method(函數上移)
- Pull Up Constructor Body(構造函數本體上移)
- Push Down Method(函數下移)
- Push Down Field(值域下移)
- Extract Subclass(提煉子類)
- Extract Superclass(提煉超類)
- Extract Interface(提煉接口)
- Collapse Hierarchy(折疊繼承關系)
- Form Template Method(塑造模板函數)
- Replace Inheritance with Delegation(以委托取代繼承)
- Replace Delegation with Inheritance(以繼承取代委托)
- 章節十二 大型重構
- 這場游戲的本質
- Tease Apart Inheritance(梳理并分解繼承體系)
- Convert Procedural Design to Objects(將過程化設計轉化為對象設計)
- Separate Domain from Presentation(將領域和表述/顯示分離)
- Extract Hierarchy(提煉繼承體系)
- 章節十三 重構,復用與現實
- 現實的檢驗
- 為什么開發者不愿意重構他們的程序?
- 現實的檢驗(再論)
- 重構的資源和參考資料
- 從重構聯想到軟件復用和技術傳播
- 結語
- 參考文獻
- 章節十四 重構工具
- 使用工具進行重構
- 重構工具的技術標準(Technical Criteria )
- 重構工具的實用標準(Practical Criteria )
- 小結
- 章節十五 集成
- 參考書目