第一章: 重構第一個案例
1. 重構第一步:建立一組可靠的測試環境
2. 提取出函數: 選中區域,點選Extract method(可修改參數名,函數名,扔出異常,加入comment,),運作測試判斷是否正确. 閱讀代碼時,我經常重構.這樣随着對程式的了解逐漸加深,也會不斷把這些了解嵌入代碼中.
3. 判斷子函數的參數,将參數隻屬于特定類的子函數複制到對應類,編譯并測試
4. 移出臨時變量,編譯并測試
5. 對于循環增加的臨時變量,extract method并将循環移入.重構時不必擔心性能,優化時才需要擔心.優化時可通過插入stopwatch确定性能點,進而優化
6. 對于預測變化時的重構,盡量減少受到影響的範圍
7. 對于switch語句,使用state pattern重構,是為了需求變化時更加容易
第二章: 重構原則
修改功能和重構,無論何時都應該清楚自己戴的是哪一頂帽子.
重構之前:代碼必須在大部分情況下能正常運作
何時重構
添加功能,修改錯誤
何時不該重構
項目進入最後期限
性能
程式設計時,不需要關注性能,當編寫完成後,使用測試軟體找到hot pot,然後針對該區域進行優化
重構的難題
資料庫
通過在對象模型和資料庫模型之間插入一個隔離層
修改接口
如果該接口使用者無法控制,在接口改變時,保留原接口,設為depreciated。舊接口調用新接口實作。
第三章: 代碼的壞味道
重複代碼:
同一類中的兩個函數:extract method
同一類的兩個子類:extract method, pullup method, form template method
做同一件事的兩個不同算法:使用一個清晰的取代其他,substitute algorithm
兩個不相幹的類:将共有代碼extract class ,另一個類調用,也需要從語義上判斷該函數是否屬于一個類
large function:
讓function容易了解的關鍵是起一個好名字
每當需要以注釋解釋函數時,就将要說明的東西寫入一個函數并以函數的用途來命名它,哪怕替換後的函數比原來還長,隻要函數名上看出其用途,也應該毫不猶豫地這樣做.
方法:
99%的場合:Extract method
太多的參數和臨時變量: replace temp with query和introduce parameter object
臨時變量被多次複制:split temporary variable
該提煉哪些:
尋找注釋. 就算隻有一行代碼,如果其需要注釋,也應該将其提出到一個函數
條件: decompose conditional
循環:将循環和其内的代碼提煉到一獨立的函數
large clas
方法:
先找到彼此相關的變量(有相同字首或字尾);提煉該變量相關的代碼:extract class, move field, move method
太多參數
方法:
參數由函數計算得到:replace parameter with method
參數所在對象存在:preserve whole object
參數的對象不存在:introduce parameter object
類的職責
多種原因的變化要修改一個類:extract class
一個變化修改多個類: move field,move method
依戀情節:兩個類耦合
調用某一類過多的取值函數:move method
函數的部分:先extract method,再move method
一個函數用到多個類:先extract method, 将該函數放到用到資料最多的類
Data clumps:資料泥團
删除資料的一項,其他資料不再有意義
方法:
将這些字段 Extract class;
函數參數 introduce parameter object
不必在意隻用上字段的一部分字段。
Switch statements
單一函數中:replace parameter with explicit method
選擇條件之一是null: introduce null object
大量使用:1)extract method将switch提取到獨立函數;2)move method到多個類;3)replace type code with subclass, replace type code with state/strategy
Parallel Inheritance Hierarchies 平行繼承體系
每當為一個類增加子類,需要為另一類應增加一個子類
方法:
讓繼承體系的一個子類引用另一個體系的執行個體;move method ,move field;就可以消除引用端的繼承體系
Speculative Generality
如果函數或類的唯一使用者是測試用例
類:inline class 或者collapse hierarchy
函數的某些參數:remove parameter
函數名過于抽象:rename method
Message Chains
一長串的getThis()
觀察該函數具體的作用,将該函數放入消息鍊的正确位置
Middle Man:過度委托
某個類有一半的函數都委托給其他類
方法:
remove middle man;
少數幾個函數:inlineMethod
Incomplete Library Class:不完美的庫類
修改一兩個函數:Introduce Forign Method
增加一大堆行為:Introduce Local Extension
Data Class
除了get set 什麼也不幹
找到調用處,move method; 對不提供修改的字段 remove set method;後期可用hide method隐藏get和set
Comments
說明參數規格: introduce assertion
合理的注釋:将來的打算,為什麼要這麼做
第四章構築測試體系
寫程式最花時間的是調試錯誤,找出錯誤比較費時,改正錯誤是很快的
作用:
描寫該功能如何使用
集中于接口而非實作