重構:改善既有代碼的設計 筆記

重構的方式和流程

  • 兩頂帽子:開發的時候,開發人員經常在兩種狀態間切換,或者帶着重構的帽子重構代碼,或者帶着開發的帽子新增代碼
  • 小步前進:由於重構不改變現有代碼的邏輯,所以對於一個大功能,可以先重構一部分,測試,再接着重構一部分
  • 做好測試:重構都是修改現有代碼,那麼應當做到,以前能跑通的測試,重構後依舊可以跑通。這也是說,重構沒有問題的一個表現是,通過所有預期的測試。

代碼的壞味道(何時重構)

  • 重複代碼、異曲同工的類
  • 過長函數:要寫註釋的地方,不妨分解一個函數,用函數名說明意圖
  • 過大的類
  • 過長的參數列表:可以在函數內部通過調用其他函數得到的參數,可以不用通過入參得到
  • 發散式變化、霰彈式修改:每次變化都要修改多個函數的時候,不妨將修改的地方提取到一處或者一個類中
  • 依戀情節、狎暱關係:一個類對另一個類的數據和行爲,比對自身更感興趣,這時說明,類的功能劃分有誤
  • 數據泥團:幾項數據,通常一起出現,一起被需要,那麼,他們可能需要結成對象
  • 基本類型偏執:也許,使用小型對象,可以表示更多東西
  • switch語句:switch語句有時意味着,可以使用面向對象的繼承和多態來避免
  • 面向未來編程、暫時性字段…:當前不用的字段和僅在一定情況下使用的字段,請謹慎編寫
  • 中間類:當一個類基本把所有操作全轉接給其他類處理時,這個類的作用就有待商榷,也許可以去掉
  • 被拒絕的遺贈:父類的全部方法,子類都應該繼承,而不是選擇一部分繼承,如果是這樣,可能父類需要把某些方法下沉

重構手法

重新組織函數

  1. 提煉函數/內聯函數
  2. 引入解釋性變量保存複雜表達式結果
  3. 將不同用途的臨時變量區分開
  4. 使用函數對象取代函數:對於一個大型函數內,因爲臨時變量的緣故,函數無法拆解的情況,可以抽取函數對象,即保存變量,又有拆解的函數

對象之間搬移特性

  1. 搬移函數
  2. 搬移字段
  3. 提煉類/內聯類
  4. 隱藏委託關係/移除中間類
  5. 引入外加函數/引入本地擴展(子類或者包裝類)

重新組織數據

  1. 自封裝字段:必要時再進行
  2. 以對象取代數據值
  3. 封裝字段
  4. 封裝集合(返回不可修改的集合)
  5. 以類取代類型碼:當類型碼不影響行爲的時候,爲了運行時檢測安全,可以使用類取代類型碼
  6. 以子類取代類型碼:當類型碼影響行爲的時候,可以使用子類替代類型碼,藉助多態的優點,讓與特定類型有關的代碼下沉,這裏對類型的取值函數,可以借用自封裝字段
  7. 用狀態模式/策略模式取代類型碼:當類型碼在對象存活期間會變化時
  8. 用類型碼替代子類:當不同之處只在返回的類型碼時

簡化條件表達式

  1. 以衛語句取代嵌套條件表達式:就是將不合法的判斷前置,提前return
  2. 以多態取代條件判斷:首先,應當使用以子類/狀態模式/策略模式替代類型碼構建了繼承體系,然後將條件判斷的語句上移爲抽象函數,由子類各自實現
  3. 引入null對象:在返回null的時候,考慮可否返回一個“空對象”,以避免反覆的null校驗

簡化函數調用

  1. 移除參數:對於多態函數來說,複雜一些,需要考察是否每一個子類的實現都不需要這個參數
  2. 令函數攜帶參數/以明確函數名取代參數
  3. 以函數取代參數:函數入參可以通過調用其他參數即時獲取,則無需入參
  4. 引入參數對象:爲了抵抗前文提到的“數據泥團”
  5. 以工廠函數取代構造函數
  6. 以異常取代錯誤碼
  7. 以測試取代異常

處理概括關係

  1. 字段上移/下移
  2. 函數上移/下移
  3. 構造函數上移
  4. 摺疊繼承體系:把子類融入父類
  5. 塑造模版函數:某些函數以相同順序執行類似操作,將類似操作抽象相同簽名,則某些函數的調用可以合併爲一種,將其上移至超類
  6. 以繼承取代委託/以委託取代繼承:子類可能只需要父類的一部分功能,這時相對於繼承,組合(委託)更爲合適;反之,可以使用繼承

個人感覺很有用的重構手法

  • 使用函數對象取代函數
  • 自封裝字段
  • 以子類取代類型碼
  • 引入null對象
  • 以衛語句取代嵌套條件表達式
  • 以異常取代錯誤碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章