重構-改善既有代碼的設計

JAVA按值傳遞,給參數賦值不會改變原值,但修改參數對象會改變原對象狀態(引用)

值參數不可改

一個方法或類只承擔一個職責。

目的清晰,說明明確,讓人理解,一些潛規則,比如繼承等

1.帶來的問題:

某方法很難重用,一個相似功能就需要寫一個新的方法,結果就是兩個相似的方法存在,之後如果有改動,需要兩個同時都改,越來越複雜

2.代碼塊越小,代碼的功能就越容易管理,代碼的處理和移動也就越輕鬆

3.每個函數粒度都很小,那麼函數被複用的機會就更大,像註釋

一.步驟:

1) 建測試環境

2) 分解並重組函數

   a. 找出代碼的邏輯泥團並提成一個新的方法:沒被修改的作爲參數傳遞,修改了的如果一個可以作爲返回值

3)好的變量名是代碼清晰的關鍵,好的代碼應該清楚的表現自己的功能

4)絕大多數情況下,函數應該放在它所使用的數據的所屬對象內, 修改原先引用

5) 儘量少的臨時變量

6) switch 中的參數應該是本類中的屬性。

二.原則:

1) 事不過三,三則重構

2) 增加中間層可以解決很多問題: 

    a.允許邏輯共享

    b.分開解釋意圖和實現

    c.隔離變化

    d.封裝條件邏輯

4.壞代碼:

1) 重複代碼: 提出成一個方法

  a.子類有類似的方法: 提出到超類;如果是相似,則將變化與不變隔離

  b. 兩個不想關的類出現重複代碼:將重複代碼提煉成一個重複的類

2) 過長的函數:

  a.小函數容易理解的真正關鍵在於一個好名字

  b.每當感覺需要用註釋說明時,把需要說明的東西寫在一個獨立函數中,並以其用途命名

  c.循環和其內的代碼提煉到一個獨立函數中

3) 過大的類: 當利用單個類做太多事情,內部往往會出現太多實例變量

  a.不是一直都用所有的實例變量: 提出幾個相關的到新類中

  b.太多代碼: 先確定客戶端如何使用它們,然後爲某種方式提煉出一個接口

  c.過長的參數列表: 將參數變成對象傳過去(同時也會造成大對象和被調用對象的依賴關係)

4)針對於某一外界變化所有相應修改,都只應該發生在單一類中:一個變化需要修改多個類,一個類被多個變化影響

5)將數據和對數據的操作行爲包裝在一起,如果函數對某個類的興趣大於自己所處的類,那麼就移到那個類中。如果被幾個類依賴,拆成小方法然後移到最多依賴的類中。 將總是一起變化的東西放在一起

 6)當兩個類中有相同的字段,許多函數簽名中都有相同的參數。把他們提煉到一個獨立的對象上: 刪掉其中的一項,其餘的是否會失去意義

三.重構方式:(132)

1.過長函數:

1) 提煉函數: 困難是處理局部變量

     a.用意圖去命名:做什麼而非怎樣做

     b.原函數局部變量換成參數

     c.只是該代碼塊內部用的設爲局部變量

     d.如果改變了原類的值,需要有返回值

  2)以查詢取代臨時變量:臨時變量在類的其它部分也需要,且該臨時變量只被賦值一次(final)-->換成方法

  3)引入解釋型變量: 將該複雜表達式(或一部分)的結果放進一個臨時變量,以變量名稱來解釋表達式用途

  4)分解臨時變量: 某個變量被賦值超過一次,把該變量拆成兩個變量。每個臨時變量只承擔一個責任,用final試驗

  5) 移除對參數的賦值: 如果傳的非對象,那麼以一個臨時變量取代該參數的位置,返回該臨時變量

  6) 面對一個大型函數,由於局部變量很多無法提出成小的方法,以函數對象取代函數:將這個函數變成一個對象,所有的臨時變量爲這個類的屬性,這樣就不用再傳遞參數,然後再提

四.在對象之間搬移特性: 

  1.搬移函數:使用另一個對象的次數比使用自己所駐對象的次數還多

  2.提煉類:類的職責過多,提出子類

  3.本地擴展,原類需要添加職責,所以建立新類,導入原有類,在新類中加新方法

  4.以對象取代數據值: 有一個數據項,需要與其它數據和行爲(方法)一起使用纔有意義。197

  5.以對象取代數組: 有一個數組,但其中的元素各自代表不同的東西:以對象替換數組。對於數組的每個元素,以一個字段來表示(意義更清晰)

  6.以字面常量取代魔法數: 有一個字面數值,帶有特別的含義:創造一個常量,根據其意義爲它命名,並將上述的字面數值替換爲這個常量

  7.以子類取代類型碼: 有不可變的類型碼,影響類的行爲(一個類中有多個同質的類型):以子類取代這個類型碼(整體替代)/用策略模式替代(部分替代) -> 工廠

五.簡化條件表達式:

  1.分解條件表達式: if - else if -- ... -- else : 從if,else if,else三個段落中分別提煉出獨立的函數  邏輯清晰,體現代碼意圖

  2.合併條件表達式: 有一系列測試都得到相同的結果:用與或關於合成一個條件表達式,並將這個條件表達式提煉成一個獨立函數(意思是一起的)

  3.合併重複的條件片段: 在條件表達式的每個分支上都有着相同的一段代碼:將這段重複的代碼搬移到條件表達式之外.這樣才能清晰的表現出哪些隨條件的變化而變化,哪些東西保持不變

  4.以衛語句取代嵌套表達式: 如果某個條件極爲罕見,就應該提出來單獨檢查,而非if-else (告訴讀者這個很罕見,不平等)

六.簡化函數調用: 

  1. 函數改名: 給函數寫上註釋,然後把註釋變成函數名(304)

  2. 令函數攜帶參數 建立單一函數,以參數表達那些不同值 ---> 消去重複

  3.保持對象完整: 從對象裏取出若干值,將它們作爲某一次函數調用時的參數 --->傳遞整個對象(因爲有可能調用其它的值)

  4.減少參數長度: 如果該函數參數由另一個函數獲得,讓該函數直接調用那個函數

  5.引入參數對象:某些參數總是很自然地同時出現---->以一個對象取代這些參數,解決數據泥團

  6.當一個函數沒有被其它任何類用到,將這個函數設置爲private

  7.以異常取代錯誤碼: 異常只用來處理意料之外的行爲

七.處理概括關係

  1.如果兩個子類擁有相同的字段:將該字段移至超類

  2.函數上移:某些函數在各個子類中產生完全相同的結果--->將該函數移至超類  (避免修改了一個沒有修改另一個)

  3.構造函數本地上移:子類中的構造函數有共通點--->在父類建造一個新的構造函數,在子類構造函數中調用它

  4.塑造模板函數:子類中某些操作執行順序相同,細節不同-->將這些操作分別放到獨立函數中,起相同的函數簽名,將原函數上移至超類

  5.以委託取代繼承:某子類只用超類一部分接口-->子類中添加超類引用屬性,將繼承改爲委託

 八.大型重構:384

  1.某個繼承體系同時承擔兩種責任:建立兩個繼承體系,並通過委託關係讓一個調用另外一個

  2.將過程化設計轉化爲對象設計:將數據記錄變爲對象,將大塊行爲分成小塊,並將行爲移入相關對象中

  3.將領域和表述/顯示分離: 將領域邏輯分離出來,爲它們建立獨立的領域類

  4.提煉繼承體系:建立繼承體系,以一個子類表示一種特殊情況


發佈了9 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章