壞的味道:指的是應該被修改,被重構的代碼,不具備可讀性,複用性,判斷邏輯複雜,冗餘代碼。應該使用各類重構的手法去改變它!
若是你在一個以上的地點看到相同的程序結構,那麼能夠確定的:設法將他們合而爲一,程序會變得更好。
Duplicated Code
應該考慮對其中一個將重複代碼提煉到一個獨立類種,而後在另外一個類內使用這個新類。咱們應當遵循這樣一條原則:每當感受須要以註釋來講明點什麼的時候,咱們就須要說明的東西寫進一個獨立的函數中,並以器用途(而非實現手法)命名。
Decompose Conditional
處理條件表達是。至於循環,你應該將循環和期內的代碼提煉導一個獨立的函數中若是已有的對象發出一條請求就能夠取代一個參數,那麼你應該激活重構手法Replace Paramter with Method
。在這裏,「已有的對象」可能時函數所屬類內一個字段,也多是另外一個參數。你也能夠運用Preserve Whole Object
未來自同一個對象的一堆數據收集起來,並以該對象替換它們。若是某些數據缺少合理的對象歸屬,可使用Introduce Parameter Object
爲它們製造出一個「參數對象」。安全
一旦須要修改,咱們但願可以跳到系統的某一點, 只在該處作修改。若是不能作到這點,你就嗅出兩種相關的刺鼻味道中的一種了。
Extract Class
將它們提煉導另外一個類中。遇到某種變化,你都必須在不一樣類內作出許多小修改,你所面臨的壞味道就是shotgun Surgery,若是須要修改的代碼散佈四處,你不但很難找到它們,也很容易忘記某個重要的修改
Move Method
和Move Field
把全部須要修改的代碼放進同一個類。若是眼下沒有合適的類能夠安置這些代碼,就創造一個。一般能夠運用inline class把一系列相關行爲放進同一個類。Divergent change
是指「一個類受多種變化影響」,shotgun surgery
則是指「一種變化引起多個類相應修改」。者兩種狀況下你都會但願整理代碼,使「外界變化」與「須要修改的類」趨於一一對應。函數對某個類的興趣高過對本身所處類的興趣,一般焦點即是數據,某個函數爲了計算某個值,從另外一個對象那調用幾乎半打的額取值函數。
對象的一個極大的價值在於:它們模糊(甚至打破)了橫亙於基本類型數據和體積較大類之間的界限
Replace Data Vlaue with Object
將本來單獨存在的數據值替換爲對象Replace type Code with class
將它替換Replace Type Code with Subclass 或 Replace Type Code with State/Strategy
大多數時候,一看到switch語句,你就應該考慮以多態來替換它。問題是多態應該出如今哪兒?switch語句經常根據類型碼進行選擇,你要的是「與該類型碼相關的函數或類」session
是
Shotgun Surgery
的特殊狀況,在這種狀況下,每當你爲某個類增長一個子類,也必須爲另外一個類相應的增長一個子類。若是你發現某個繼承體系的名稱前綴和另外一個繼承體系名稱前綴徹底相同,即是聞到了這種壞味道
消除這種重複性的通常策略是:讓一個繼承體系的實例引用另外一個繼承體系的實例。再運用Move Method 和Move Field
,就能夠就將引用端的繼承體系消弭於無形app
若是一個類的所得不值其身價,它就該消失
若是某些子類沒有作足夠的工做,試試Collapse Hierarchy
。對於幾乎沒用的組件,你應該以Inline Class
對付它們ide
不要過度對的爲將來考慮
若是你的某個抽象類其實沒有太大做用,請運用Collapse Hierarchy
。沒必要要的委託可運用Inline Class
除掉。若是函數的某些參數違背用上,可對它實施Remove Parameter
。若是函數名稱帶有多餘的抽象意味,應該對它實施rename Method
,讓它現實一點
某個實例變量僅爲某種特定的狀況而設。這樣的代碼讓人不易理解,由於你一般認爲對象在全部時候都須要它的全部變量,在未被使用的狀況下猜想當初其設置目的,會讓你發瘋的。把全部和這個變量相關的代碼新建一個類放入。函數
若是你看到用戶一個對象請求另外一個對象,而後後者請求另外一個對象,而後再請求另外一個對象這就是消息鏈
先觀察消息鏈最終獲得的對象用來幹什麼的,看看可否以Extract Method
把使用該對象的代碼提煉到一個獨立的函數中再運用Move Method
把這個函數推入消息鏈code
人們可能過分運用委託,會有某個接口有一半的函數都委託給其餘類,這樣就是過分運用, 使用
Remove Middle Man
,直接和真正負責的對象打交道
Move Method
和 Move Field
幫它們劃分界限, 從而減小狎暱行徑. 你能夠能夠看看是否能夠運用Change Bidirectional Association to Unidirectional
(將雙向關聯改成單向關聯)讓其中一個類對另外一個斬斷情絲.Extract Class
把二者的共同點提煉到一個安全的地點,讓它們坦蕩地使用這個新類. 或者也能夠嘗試運用Hide Delegate
讓另外一個類來爲它們傳遞相思情.Replace Inheritance with Delegation
讓它離開繼承體系.若是兩個函數作同一件事,卻有着不一樣的簽名,請運用Rename Method
根據它們的用途從新命名。但這每每不夠,請反覆運用 Move Method
將某些行爲移入類,直到2者的協議一致爲止。若是你必須反覆而贅餘的移入代碼才能完成這些,或許可運用Extract SuperClass
對象
若是隻想修改類庫的一兩個函數,能夠運用Introduce Foreign Method
若是想要添加一大堆額外行爲,就得運用Introduce Local Extension
繼承
所謂Data Class是指:它們擁有一些值域(fields),以及用於訪問(讀寫〕這些值域的函數,除此以外一無長物。
Encapsulate Collection
(封裝羣集) 把它們封裝起來。對於那些不應被其餘classes修改的值域,請運用 Remove Setting Method
(移除設置函數)。getting and setting methods
)被其餘classes運用的地點。嘗試以Move Method
(搬移函數) 把那些調用行爲搬移到Data Class來。若是沒法搬移整個函數,就運用 Extract Method
(提煉函數) 產生一個可被搬移的函數。不久以後你就能夠運用Hide Method
(隱藏某個函數)把這些「取值/設值」函數隱藏起來了。指的是一個子類,不須要父類中的過多方法
這樣咱們能夠爲這個子類建立一個兄弟類,把父類中不須要的方法下移到兄弟類中去。 若是子類複用了超類的行爲(實現),卻又不肯意支持超類的接口。不過即便不肯意繼承接口,也不要胡亂修改繼承體系,應該運用Replace Inheritance with Delegation
來達到目的接口
引用做者的一句話"當你感受須要撰寫註釋,請先嚐試重構,試着讓全部註釋都變得多餘。"
並非說寫註釋很差,而是當你寫一段很長的註釋來講明代碼邏輯的時候,說明這段代碼真的很糟糕,你就要考慮重構了。 ci