梳理并分解繼承體系
某個繼承體系同時承擔兩項責任,那么就建立兩個繼承體系,并通過委托關系讓其中一個可以調用另一個。
梳理后,重構為:
做法:
- 首先識別出繼承體系所承擔的不同責任,然后建立一個二維表格(或者三維表格乃至四維表格,。。),并以坐標軸標示出不同的任務,我們將重復利用此重構,處理兩個或者兩個以上的重構(每次只處理一個維度)。
- 判斷哪一項重構更重要,并準備將它留在當前繼承體系中,準備將另一項責任移到另一個繼承體系。
- 使用Extract Class 從當前的超類提煉出一個新類,用以表示重要性稍低的責任并在源超類中添加一個示例變量,用以保存新類的實例。
- 對應于原繼承體系中的每個子類,對應的創(chuàng)建上述新建的一個子類,在源繼承體系的子類中,將前一步所添加的實例變量初始化為新建子類實例。
- 針對原繼承體系的每個子類,使用Move Method 將其中的行為搬移到與之對應的新建子類中。
- 當源繼承體系中的某個子類不再具有任何代碼時,就去除它。
- 重復上述步驟,直到源繼承體系中所有子類都被處理為止,觀察新繼承體系,看看是否可能對它實施重構手法【繼承體系重構手法】。
Convert Procedural Design to Objects(將過程化設計轉化為對象設計)
有一些傳統(tǒng)過程化風格的代碼,將數(shù)據(jù)記錄變成對象,將大塊的行為分成小塊,并將行為移入相關的對象中
做法
- 針對每一個記錄類型,將其轉化成只含有訪問原函數(shù)的啞數(shù)據(jù)對象
如果你的數(shù)據(jù)來自關系型數(shù)據(jù)庫,就把數(shù)據(jù)庫中的每一個表變成啞數(shù)據(jù)對像 - 針對每一處過程化風格,將該處的代碼提煉到一個獨立函數(shù)
可以把提煉的類做成一個Singleton(為了方便重新初始化),或提煉所得的函數(shù)聲明為static - 針對每一段長長的程序,實施Extract Method及其他相關的重構將它分解,在以Move Method將分解后的函數(shù)移動到相關的啞對象中
- 重復上述步驟,直到原始類的所有函數(shù)都被移除,如果原始類是一個過程化類,一定要移除。
Separate Domain from Presentation(將業(yè)務/領域和表述/顯示分離)
某些GUI類之中包含了領域邏輯。將領域邏輯分離出來,為他們建立獨立的領域類.
做法
- 為每一個窗口建立一個領域類.
- 如果窗口內有一張表格,新建一個類來表示其中的性=行,再以窗口所對應之領域類中的一個集合來容納所有的行領域對象
- 檢查窗口中的數(shù)據(jù),如果數(shù)據(jù)只被用于UI,就把它留著;如果數(shù)據(jù)被領域邏輯使用,而且不顯示于窗口上,我們就以Move Field將它搬移到領域類中;如果數(shù)據(jù)同時被UI和領域類使用,就對他實施Duplicate Obsersed Data,使它同時存在于兩處,并保持兩處之間的同步。
- 檢查展現(xiàn)類中的邏輯,實施Extract Method將展現(xiàn)邏輯從領域邏輯中分開,一旦隔離了領域邏輯,在運用Move Method 將它移動到領域類
- 以上步驟完成之后,你就擁有了兩組類.
Extract Hierarchy(提煉繼承體系)
你有某個類做了太多工作,其中一部分工作是以大量條件表達式完成的。
建立繼承體系,以一個子類來表示一種特殊情況。
在漸進式設計過程中,常常會有這樣的情況:一開始設計者只想以一個類實現(xiàn)一個概念;但隨著設計方案的演化,最后卻可能一個類實現(xiàn)了兩個、三個乃至十個不同的概念。一開始,你建立了這個簡單的類。數(shù)天或數(shù)周之后,你可能發(fā)現(xiàn):只要加入一個標記和一兩個測試,就可以在另一個環(huán)境下使用這個類;一個月之后你又發(fā)現(xiàn)了另一個這樣的機會;一年之后,這個類就完全一團糟了:標記變得和條件表達式遍布各處。
當你遇到這種瑞士軍刀般的類--不但能夠開瓶開罐、砍小樹枝、還能在演示會上打出激光強調重點--你就需要一個好策略(亦如本項重構),將它的各個功能梳理并分開。不過,請注意,只有當條件邏輯在對象的整個生命周期保持不變,本重構導入的策略才適用。否則你可能必須在分離各種狀況之前先使用Extract Class
Extract Hierarchy 是一項大型重構,如果你一天之內不足以完成它,不要因此失去勇氣。將一個極度混亂的設計方案梳理出來,可能需要數(shù)周甚至數(shù)月的時間。你可以先進行本項重構中的一些簡易步驟,稍微休息一下,再花幾天時間編寫一些能體現(xiàn)產出的代碼。當你領悟到更多東西,再回來繼續(xù)本項重構的其他步驟--這些步驟將因為你的領悟而顯得更加簡單明了。
做法
我們?yōu)槟銣蕚淞藘山M重構手法。第一種情況是:你無法確定哪些地方會發(fā)生變化。這時候你會希望每次一小步地前進。
- 鑒別出一種變化情況。
如果這種變化可能在對象聲明周期的不同階段而有不同體現(xiàn),就運用Extract Class 將它提煉為一個獨立的類。 - 針對這種變化情況,新建一個子類,并對原始類實施Replace Constructor with Factory Method。再修改工廠函數(shù),令它返回適當?shù)淖宇悓嵗?/li>
- 將含有條件邏輯的函數(shù),一次一個,逐一復制到子類,然后在明確情況下(對子類明確,對超類不明確),簡化這些函數(shù)。
如有必要隔離函數(shù)中的條件邏輯和非條件邏輯,可對超類實施Extract Method. - 重復上述過程,將所有變化情況都分離出來,直到可以將超類聲明為抽象類為止。
- 刪除超類中那些被所有子類覆寫的函數(shù)本體,并將它們聲明為抽象函數(shù)。
如果你非常清楚原始類會有哪些變化情況,可以使用另一種做法。
- 針對原始類的每一種變化情況,建立一個子類。
- 使用Replace Constructor with Factory Method將原始類的構造函數(shù)轉變成工廠函數(shù),并令它對每一種變化返回適當?shù)淖宇悓嵗?br> 如果原始類中的各種變化情況是以類型碼表示,先使用Replace Type Code with Subclass;如果那些變化情況在對象生命周期的不同階段會有不同體現(xiàn),請使用Replace Type Code with State/Strategy。
- 針對帶有條件邏輯的函數(shù),實施Replace Conditional with Polymorphism 。如果并非整個函數(shù)的行為有所變化,而只是函數(shù)一部分有所變化,請先運用Extract Method將變化部分和不變部分分隔開來。