重構-改善既有代碼設計

  1. 重構是在不改變軟件可觀察行爲的前提下,對代碼做出修改,以改進程序的內部結構。本質上說就是在代碼寫好後改進它的設計
    重構每每意味着不瞭解軟件行爲下重構程序
    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.學習原路返回
    程序員

相關文章
相關標籤/搜索