重構是在不改變軟件可觀察行爲的前提下,對代碼做出修改,以改進程序的內部結構。本質上說就是在代碼寫好後改進它的設計
重構每每意味着不瞭解軟件行爲下重構程序
2.在設計前期使用模式經常致使過分工程,單憑對完美的追求沒法寫出實用的代碼,而"實用"是軟件壓倒一切的要素
《設計模式》指出:設計模式爲重構提供類目標
重構能夠反"軟件會慢慢腐爛"現象,經過重構,設計再也不是一切動做的前提,而是在整個軟件開發過程當中逐漸浮現出來
【29頁】 若是你發現本身須要爲程序添加一個特性,而代碼結構使你沒法很方便地達成目的,那就先重構那個程序,使特性的添加比較容易進行,而後再添加特性。
【35頁】 重構技術就是以微小的步伐修改程序。若是你犯下錯誤,很容易發現。
【37頁】 任何一個傻瓜均可以寫出計算機能夠理解的代碼,惟有寫出人類容易理解的代碼,纔是優秀的程序員。
第二章:
重構(名詞):對軟件內部結構的一種調整,目的是在不改變軟件可觀察行爲的前提下,提升其可理解性,下降其修改爲本。
重構(動詞):使用一系列重構手法,在不改變軟件可觀察行爲的前提下,調整其結構。
兩頂帽子:使用重構技術開發軟件時,你把時間分配給兩種大相徑庭的行爲:添加新功能,以及重構,添加新功能時只能添加新功能,不能修改已有代碼;
重構時,只管改進程序結構,不能添加新功能
爲什麼重構?1.重構改進軟件設計[防止軟件腐爛] 2.重構使軟件更容易理解[給人理解] 3.重構提升編程速度
重構的時機:重構應該隨時隨地進行,你不能爲了重構而重構,你之因此向重構,是由於你想作別的事情,而重構能夠幫你把那件事作好
三次法則:第一次作某件事時只管去作;第二次作相似的事會產生反感,但不管如何仍是能夠去作;第三次再作相似的事,你就應該重構[事不過三,不然重構]
A添加功能時重構 B修補錯誤時重構 C代碼複審時重構[二人代碼重構,多人則設計重構]
《數據庫重構》
不要過早發佈接口,請修改你的代碼全部權政策,使重構更順暢。
【88頁】什麼時候不能重構
1.原有代碼壓根不能正常運行 2.項目接近最後期限,項目接近後期時重構,爲時已晚
2.重構與設計,重構肩負一項特殊使命:重構與設計彼此互補
【kent,XP,極限編程】:重構能夠取代預先設計。這意思是你根本沒必要作任何設計,只管按照最初想法開始編碼,讓代碼有效運做,而後再將它重構
成型。事實上這種辦法真的可行。
3重構與性能:咱們猜想的性能瓶頸每每不是消耗性能的真正所在,只有經過測試才能找到真正影響性能的地方,並把時間用在真正須要優化的地方
第三章:"壞味道"<須要重構之處>
1.重複代碼
2.過長的函數
3.過大的類[單個類作了不少的事情]
4.過長的參數列
5.發散式變化[一個類受多種變化的影響]
6.三彈式修改[一種變化引發多個類的修改]
7.依戀情節[一個類的某個函數使用的大部分數據來源於其餘類]
8.數據泥團[兩個類中相同的字段,許多函數簽名中相同的參數]
9.基本類型偏執[或許你不肯意將一些基本數據類型轉換爲對象]【104頁】
10.switch驚悚現身[多態替換switch]
11.平行繼承體系[每當你爲一個類增長一個子類的同時也須要爲另外一個類增長子類]
12.冗餘的類[沒什麼實際做用的類]
13.誇誇其談的將來性[爲了將來變化而準備的接口]
14.使人迷惑的臨時變量
15.過分耦合的消息鏈[一個對象傳遞了很遠才獲得處理]
16.中間人[一些類的大部分業務都是調用其餘類實現的]
17.狎呢關係[過分親密的類,如繼承]
18.殊途同歸的接口[功能相似的函數]
19.不完美的庫類
20.數據類[簡單包含字段和getter與setter方法的類]
21.被拒絕的饋贈[子類不想繼承所有的函數]
22.過多的註釋[儘可能用表意的方法簽名代替註釋]【當你感受須要撰寫註釋時,請先嚐試重構,試着讓全部註釋多餘】
第四章:構築測試體系
4.1自測試代碼的價值:xiug修復錯誤只須要很短的時間,但找到錯誤卻須要不少的時間
【確保全部測試都徹底自動化,讓它們檢查本身的測試結果】
【一套測試就是一個強大的bug偵測器,可以大大縮短查找bug所須要的時間】
【每當你收到bug,請先寫一個單元測試來暴露bug】
4.3添加更多測試
【考慮可能出錯的邊界條件,把測試火力集中在那兒】[不要爲每個函數寫測試,只爲那些可能出錯的地方寫測試]
【不要由於測試沒法捕捉全部的bug就不寫測試,由於測試的確能夠捕捉到大多數bug】
第五章:重構列表
5.2:尋找引用點[發射不能找到,繼承覆蓋不能找到]
第六章:從新組織函數
1.Extract Method-提煉函數:將代碼放進一個獨立函數中,並讓函數名稱解釋該函數的用途
2.Inline Method-內聯函數:在函數調用點插入函數主體,而後移除該函數
3.Inline Temp-內聯臨時變量:將全部對該變量的引用動做,替換爲對他賦值的表達式自身
4.Replace Temp with Query-以查詢取代臨時變量:將臨時變量換成相應的賦值方法
5.Introduce Explaining Variable-引入解釋性變量:將複雜表達式的結果放進一個臨時變量,以此變量名稱來解釋變量用途
6.Split Temporary Variable-分解臨時變量:[有些臨時變量被屢次賦值],針對每次賦值都創造一個新符臨時變量
7.Remove Assignments to Parameters-移除對參數的賦值:[方法修改了參數]以一個臨時變量取代該參數的位置
8.Replace Method with Method Object-以函數對象取代函數:將這個函數放進一個單獨的類中,如此一來局部變量就成了對象的字段。
而後你能夠在同一個對象中將這個大型函數分解爲多個小型函數
9.Substitute Algorithm-替換算法:將函數本體替換爲另外一種算法
第七章:在對象之間搬移特性
1.Move Method-搬移函數:[一個類的某個函數與另外一個類交流更多,此時,該函數極有多是放錯地方了]
在該函數最常引用的類中創建一個有着相似行爲的新函數。將舊函數變成一個單純的委託函數,或是將舊函數徹底移除
2.Move Field-搬移字段:[你的類的字段與另外一個類更多交流,此時,這個字段是否是放錯地方了]
在目標類新建一個字段,修改源字段的全部用戶,令它們改用新字段
3.Extract Class-提煉類:[某個類作了應該由兩個類作的事]
創建一個新類,將相關的字段和函數從舊類搬移到新類
4.Inline Class-將類內聯化:將一個類的全部特性所有搬到另外一個類中[這個類沒幹什麼實事]
5.Hide Delegate-隱藏委託關係:在服務類上創建所需的全部函數,用以隱藏委託關係[最少知識原則,例如System.out.print()]
6.Remove Middle Man-移除中間人:某個類的大部分操做都是委託實現的,讓調用者直接調用受託類
7.Introduce Foreign Method-引入外加函數:在客戶類中創建一個函數,並以第一參數形式傳入一個服務類實例。
[你須要爲提供服務的類增長一個函數,但你沒法修改這個類---不完美的庫類]
第八章:從新組織數據
1.Self Encapsulate Field-自封裝字段:爲這個字段創建setter和getter函數[你直接訪問一個字段,但與字段之間的耦合關係逐漸變得笨拙]
2.Replace Data Value with Object-以對象取代數據值:將數據項變成對象[你有一個數據項,須要與其餘數據和行爲一塊兒使用纔有意義]
3.Change Value to Reference-將值對象改成引用對象:將值對象改成引用對象
4.Change Reference to Value-將引用對象改成值對象:將對象改成值對象[你有一個很小的對象,不可改變同時不易管理]
5.Replace Array with Object-以對象取代數組:以對象替換數組。對於數組中每個元素,以一個字段表示[用數組表示不一樣意義的數據]
6.Duplicate Observed Data-複製"被監視數據":將該數據複製到一個領域對象中。創建一個Observed模式,用以同步領域對象和GUI對象內的重複數據
7.Change Unidirectional Association to Bidirectional-將單向關聯改成雙向關聯
8.將雙向關聯改成單向關聯:(儘可能除去不須要的關聯)
9.以字面量取代魔法數:常量的運用
10.Encapsulate Field-封裝字段:getter和setter封裝public字段
11.Encapsulate Collection-封裝集合:(不要直接把集合從方法返回出去)
12.Replace Record with Data CLass-以數據類取代記錄:相似於數據庫實體
13.以類取代類型碼:以一個新的類替換該數值類型碼
14.以子類型取代類型碼
15.以State/Strategy取代類型碼
16.以字段取代子類:[子類只返回一些狀態字段]
第九章:簡化條件表達式
1.分解條件表達式:從if,else,then中分別提煉出獨立函數
2.合併條件表達式:將相同處理狀況的條件表達式合併,並用獨立函數處理條件下的操做
3.合併重複的條件判斷:全部條件下都會執行的代碼片斷應該合併並提取爲獨立函數
4.移除控制標記:用break,return等取代循環退出標記
5.以衛語句取代嵌套條件表達式:使用衛語句表現全部的特殊狀況(衛語句:特殊檢查)
6.以多態取代條件表達式
7.引入Null對象
8.引入斷言
第十章:簡化函數調用
1.Rename method-函數更名
2.Add Parameter-添加參數
3.Remove Paramter-移除參數
4.Separate Query from Modifer-將查詢函數與修改函數分離
5.令函數攜帶參數:不一樣的函數功能類似,添加參數進行區別
6.以明確函數取代參數:針對參數的每個可能值,創建一個獨立函數
7.Preserve Whole Object-保持對象完整:參數改成整個對象[你須要對象中的某幾個字段做爲參數]
8.以函數取代參數
9.引入參數對象:某些參數老是同時出現
10.Remove Setting Method-移除設值參數
11.Hide Method-隱藏參數
12.以工廠函數取代構造函數
13.封裝向下轉型:不要讓函數調用者轉換函數函數的返回值
14.異常取代錯誤碼
15.以測試取代異常
第十二章:處理歸納關係
1.Pull Up Field-字段上移:將字段移至超類[兩個子類擁有相同字段]
2.Pull Up Methid-函數上移:將函數移至超類[有些函數,在各個子類中產生徹底相同的結果]
3.構造函數上移:在超類中新建一個構造函數,並在子類構造函數中調用它[各個子類的構造函數的本體幾乎徹底同樣]
4.函數下移:將函數移到相關的子類去[超類中的某個函數只與部分(而非所有)子類有關]
5.字段下移:將這個字段移到須要它的那些子類去
6.提煉子類:[類中的某些特性只被部分實例用到]新建一個子類,將上面所說的那一部分特性移到子類中
7.提煉超類:[兩個類有類似特性]爲這兩個類創建一個超類,將相同特性移至超類
8.提煉接口:[若干客戶使用類接口中的同一子集,或者兩個類的接口有部分相同]將相同的子集提煉到一個獨立接口中
9.摺疊繼承關係:[超類和子類之間並沒有太大區別]將它們合爲一體
10.塑造模板函數:[你有一些子類,其中相應的某些函數以相同順序執行操做,但各個操做上的細節上有所不一樣]使用模板模式
11.委託取代繼承:[某個子類只使用超類接口中的一部分,或者根本不須要繼承而來的數據]子類中保存超類的引用,操做委託超類,取消繼承關係
12.以繼承取代委託:[你在兩個類之間使用委託,並常常爲整個接口編寫許多極簡單的委託函數]讓委託類繼承受託類
第十二章:大型重構
1.隨時重構,而不是專門花時間作一些有風險的事
1.梳理並分解繼承體系:[某個繼承體系同時承擔兩項責任]創建兩個繼承體系,並經過委託關係讓其中一個能夠調用另外一個
2.將過程化設計轉化爲對象設計:[你手上有一些傳統過程化風格的代碼]將數據記錄變成對象,將大塊的行爲分爲小塊,並將行爲移入相關對象中
3.將領域和表述/現實分離:[某些GUI類之中包含了領域邏輯]將領域邏輯分離出來,爲它們創建獨立的領域類
4.提煉繼承體系:[你有某個類作了太多工做,其中一部分工做是以大量條件表達式完成的]創建繼承體系,以一個子類表示一種特殊狀況
第十五章:總結
1.隨時挑一個目標進行重構
2.沒把握就停下來
3.學習原路返回
程序員