基類中的某個函數只與部分(並非全部)子類有關。將這個函數移到相關的那些子類去。 ...
本小節目錄
4Push Down Method(函數下移)
概要
基類中的某個函數只與部分(並非全部)子類有關。
將這個函數移到相關的那些子類去。
動機
Push Down Method與Pull Up Method恰恰相反。當我有必要把某些行為從基類中移至特定的子類時,就使用Push Down Method,它通常也只在這種時候有用。使用Extract Subclass之後可能會需要它。
範例
如下代碼所示,Animal類中的方法Bark()只有在其子類Dog中使用,所以最好的方案就是把這個方法移到子類Dog中。
public class Animal { public void Bark() { // code to bark } } public class Dog : Animal { } public class Cat : Animal { }
重構後的代碼如下,同時在父類Animal中如果沒有其他的欄位或者公用方法的話,可以考慮把Bark()方法做成一個介面,從而去掉Animal類。
public class Animal { } public class Dog : Animal { public void Bark() { // code to bark } } public class Cat : Animal { }
小結
面向對象三大特征(繼承、封裝、多態)很多時候可以幫助我們,但同時也可能會造成使用過度或者使用不當,所以如何把握好設計,這個就變得至關重要。在什麼時候使用繼承的方式,在什麼時候使用組合和聚合,介面和繼承類的選擇等就成了我們的重點。
5Push Down Field(欄位下移)
概要
基類中的某個欄位只被部分(並非全部)子類用到。
將這個欄位移到需要它的那些子類去。
動機
如果只有某些(而非全部)子類需要基類內的一個欄位,就可以使用本項重構。
範例
如下代碼所示,基類Task類中的_resolution欄位只會在子類BugTask中用到,所以就考慮把它放到BugTask類中。
public class Task { protected string _resolution; } public class BugTask : Task { } public class FeatureTask : Task { }
重構後的代碼如下所示,這樣做的好處可以簡化基類,同時讓其他沒有使用它的子類也變得更加簡單,如果這樣的欄位比較多的話,使用此重構也能節約一部分記憶體。
public class Task { } public class BugTask : Task { protected string _resolution; } public class FeatureTask : Task { }
小結
此重構也是一個非常簡單的重構,在很多時候我們都會不自覺的使用它。
6Extract Subclass(提煉子類)
概要
類中的某些特性只被某些(而非全部)實例用到。
新建一個子類,將上面所說的那一部分特性轉移到子類中。
動機
使用本項重構的主要動機是:你發現類中的某些行為只被一部分實例用到,其他實例不需要它們。
Extract Class是Extract Subclass之外的另一種選擇,兩者之間的抉擇其實就是委托和繼承之間的抉擇。Extract Subclass通常更容易進行,但它也有限制:一旦對象創建完成,你無法再改變與類型相關的行為。但如果使用Extract Class,你只需插入另一個組件就可以改變對象的行為。此外,子類只能用以表現一組變化。如果你希望一個類以幾種不同的方式變化,就必須使用委托。
範例
當你的基類中存在一些方法不是所有的子類都需要訪問,你想將它們調整到子類中時,這個重構會變得很有用了。如下代碼所示,我們需要一個 Registration類用來處理學生選課的信息。但是當Registration類開始工作後,我們意識到我們會在兩種不同的上下文中使用Registration類,NonRegistrationAction和Notes只有在我們處理未註冊情況下才用到。
public class Registration { public NonRegistrationAction Action { get; set; } public decimal RegistrationTotal { get; set; } public string Notes { get; set; } public string Description { get; set; } public DateTime RegistrationDate { get; set; } }
重構後的代碼如下所示,這樣也滿足面向對象五大原則之一的單一職責。同時也讓類的結構變得更加清晰,增強了可維護性。
public class Registration { public decimal RegistrationTotal { get; set; } public string Description { get; set; } public DateTime RegistrationDate { get; set; } } public class NonRegistration : Registration { public NonRegistrationAction Action { get; set; } public string Notes { get; set; } }
小結
這個重構方法經常用來規範類的職責,和之前的一些重構方法也有些類似。
To Be Continued……