3.1 重複代碼(若是須要修改該段代碼,那麼須要修改不少地方,容易致使問題。不易維護。)算法
若是一個類的兩個函數有相同的表達式,能夠將表達式提煉成函數,兩個地方分別調用這個函數。設計模式
若是是兩個子類中有相同表達式,將表達式提煉成函數,推入超類。若是代碼只是相似,提煉函數的時候須要將類似部分和差別部分分割,構成一個單獨函數。其中可能能夠運用塑造模板函數或這個模板方法設計模式。數組
若是有些函數以不一樣算法作相同的事情,能夠選擇較清晰的一個,使用替換算法將其替換掉。函數
若是是兩個絕不相干的類出現重複代碼,能夠考慮對其中一個提煉成新類,另外一個類調用這個新類。測試
3.2 過長函數 (函數過長通常說明函數作了太多的事情,違背了單一職責原則。將函數分解成更細粒度的函數,易於改造和使用。)設計
每當感受須要以註釋來講明點什麼的時候,咱們就把須要說明的東西寫進一個獨立函數中,並用其用途命名。(代碼比較難懂的時候)對象
百分之九十九的場合,要把函數變小,只須要使用提煉函數找到函數適合集中在一塊兒的部分(除了提煉函數,還須要考慮函數存放的位置)繼承
若是提煉函數的新函數中內存在大量臨時變量和參數,能夠經過用查詢替代臨時變量來消除臨時元素(若是查詢不耗費資源和時間,通常來講建立臨時變量須要分配額外的地址,建立太多臨時變量會浪費不少系統資源,用查詢替換臨時變量會節省地址空間。固然不是說徹底不能使用臨時變量,若是使用臨時變量能夠方便理解代碼也可使用,可是慎用。太多臨時變量可能會致使問題)。也可使用引入參數對象,或者保持對象完整來使過長的參數列變得簡潔一些。接口
若是作了上述操做以後仍是有太多臨時變量和參數,那就應該使用函數對象替代函數。內存
那些部分須要提煉
1、尋找註釋,有註釋的地方通常說明這個地方很差理解。而很差理解的緣由極可能是作了額外的事情。這就須要提煉出來
2、條件表達式和循環。條件表達式能夠經過分解表達式來處理。循環和循環內的代碼須要提煉成函數。
3.3 過大的類 (若是類須要作的事情不少,容易出現大量實例變量,那麼緊接着就會出現大量重複的代碼)
將幾個變量提煉到新類,提煉的時候儘可能選擇相關的變量。
若是一個類有太多代碼,每每適合使用提煉類或者提煉子類。這裏有個技巧,先肯定客戶端如何使用,而後運用提煉接口爲每一種方式提煉出一個接口。
3.4 過長的參數列(參數過多,函數使用成本變高,由於若是沒有函數須要的參數就沒法調用函數)
若是參數大部分來自一個對象,那麼能夠直接傳入這個對象。從對象裏獲取參數。若是能夠經過給對象發送請求能夠獲取參數,那麼應該使用函數替換參數。使用保持對象完整未來自同一個對象的一堆數據收集起來,用該對象替換他們。若是數據缺少合理的對象歸屬,可使用引用參數對象來爲他們建立一個」參數對象「
3.5 發散式變化 (將分裂成多個類,每一個類處理對應的變化)
針對某一外界變化的全部相應修改,應該發生在單一類中。新類的全部內容都應該反應此變化。應該找出某特定緣由形成的全部變化,而後運用提煉類將其提煉到新類。
3.6 霰彈式修改(將變化統一到同一個地方,統一修改,方便維護)
和發散式變化相反,若是遇到某個變化,須要修改的代碼分佈在四處,很難修改,並且容易忘記。應該使用移動函數和移動字段把全部修改的代碼放到同一個類中,沒有合適的類就建立一個。能夠運用將類內聯化將一系列行爲放進同一個類。
發散式變化指一個類受多種變化影響,霰彈式修改指一種變化引起多個類修改。
3.7 依戀情結(將相關的類和函數放到一塊兒,更容易管理)
函數對某個類的興趣高過自身所在的類,某個函數調用其餘類的大部分對象。須要將該函數移動到這個類中。若是隻有一部分,那麼將其提煉成函數再移動。
判斷哪一個類擁有最多被此函數使用的數據,而後將這個函數放到該類中
3.8 數據泥團 (數據間有依賴關係,建立新對象更容易管理)
兩個類中相同的字段,許多函數簽名中有相同的參數,這些老是綁在一塊兒的數據應該有本身的對象。
刪除衆多數據的一項,其餘數據有沒有失去意義,若是再也不有意義,那麼就應該爲他們產生一個新的對象。(說明這些數據之間有依賴關係)
3.9 基本類型偏執 (不要偏執於使用基礎類型,有時須要建立新的數據類型)
若是有一組應該老是放在一塊兒的字段,運用提煉類。若是參數列中有基本型數據,可使用引用參數對象,或者使用對象替換數組。
3.10 switch語句 (使用多態替換switch)
使用提煉函數將switch語句提煉到獨立函數,將函數移動到須要多態性的類中。
3.11 平行繼承體系(霰彈式修改的特例)
每當你爲某個類增長一個子類,也必須爲其餘的類增長一個子類。讓其餘類的實例引用另外一個繼承體系的實例。
3.12 冗贅類 (去掉沒有做用或者做用很小的類,可使代碼更清晰,簡潔)
若是某些子類沒有作足夠的工做,能夠試試摺疊繼承體系。對於幾乎沒用的組件,可使用將類內聯化。
3.13 誇誇其談將來性 (爲了可維護性而作了一些操做,可是卻沒有用到,我的感受和冗贅類相似)
若是類和函數的惟一用戶時測試用例,那麼能夠將其和測試用例一塊兒刪掉。
3.14 使人迷惑的臨時字段 (和過長參數列中臨時變量太多相似,太多臨時變量會讓人難以理解)
對象內的某個實例變量僅爲某種特定狀況而設,這樣的的代碼讓人不易理解。可使用提煉類存放這些變量。
過長參數列中參數中臨時變量太多也屬於這種狀況
3.15 過分耦合的消息鏈 (消息鏈中間有地方須要修改,就不易維護)
一個對象請求另外一個對象,另外一個對象再請求其餘的對象。這就是消息鏈。
先觀察消息鏈最終獲得的對象時用來幹什麼的,可否以提煉函數把使用對象的代碼提煉到一個獨立函數,再運用移動函數將其推入消息鏈。
3.16 中間人 (太多無用委託會致使類關係變得複雜)
使用刪除中間人去掉過分使用的委託。
3.17 狎暱關係 (類太親密意味這某個類修改會影響另外一個類)
兩個類太多親密,可使用移動函數和移動字段劃清界限。
3.18 殊途同歸的類 (重複的工做只須要作一次)
若是兩個類作同樣的事情,可是名稱不一樣,那麼去掉其中一個類,根據用途給另外一個類更名。
3.19 不完美的類庫
若是隻想修改庫類的一兩個函數,能夠運用引入外部方法。若是想添加一堆額外行爲,運用引入本地擴展。
3.20 數據類
擁有一些字段,以及用於訪問這些字段的函數,除此以外沒有做用
3.21 被拒絕的遺贈
若是子類複用了父類的行爲,可是不支持父類的接口。用委託取代繼承來修改這個子類。
3.22 過多的註釋
若是須要註釋一塊代碼能夠考慮提煉函數。若是已經提煉,可是仍是須要註釋,那麼能夠考慮重命名函數。若是須要註釋說明系統的需求規格試試導入斷言。