有一個函數,從來沒有被其他任何類用到。將這個函數設為private。 ...
本小節目錄
11Hide Method(隱藏函數)
概要
有一個函數,從來沒有被其他任何類用到。將這個函數設為private。
動機
重構往往促使你修改函數的可見度。提高函數可見度的情況很容易想象:另一類需要用到某個函數,因此你必須提高該函數的可見度。
當你在另一個類中移除對某個函數的調用時,就應該檢查有沒有可能降低這個函數的可見度(使它私有化)。
12Replace Constructor with Factory Method(以工廠函數取代構造函數)
概要
你希望在創建對象時不僅僅是做簡單的建構動作。將構造函數替換為工廠函數。
動機
使用本重構手法最顯而易見的動機就是在派生子類的過程中以工廠函數取代類型碼。可能常常需要根據類型碼創建相應的對象,現在,創建名單中還得加上子類,那麼子類也根據類型碼來創建。然而由於構造函數只能返回單一類型的對象,因此需要將構造函數替換為工廠函數。
範例:根據整數(實際是類型碼)創建對象
class Employee { public static int ENGINEER = 0; public static int SALESMAN = 1; public static int MANAGER = 2; private int _type; public Employee(int type) { _type = type; } }
我希望為Employee提供不同的子類,並分別給予它們相應的類型碼。因此,需要建立一個工廠函數:
public static Employee Create(int type) { return new Employee(type); }
然後,修改構造函數的所有調用點,讓它們改用上述新建的工廠函數,並將構造函數聲明為private:
Employee eng=Employee.Create(Employee.ENGINEER);
private Employee(int type) { _type = type; }
範例:根據字元串創建子類對象
迄今為止,還沒有獲得什麼實質收穫。目前的好處在於:把“對象創建請求的接收者”和“被創建對象所屬的類”分開了。隨後把類型碼轉換為Employee的子類,就可以運用工廠函數,將這些子類對用戶隱藏起來:
public static Employee Create(int type) { switch (type) { case 0: return new Engineer(); case 1: return new Salesman(); case 2: return new Manager(); default: throw new ArgumentException("Incorrect type code value."); } }
可惜的是,這裡有一個switch語句。如果添加一個新的子類,就必須記得更新這裡的switch語句。
繞過這個switch語句的一個好辦法是使用反射。第一件要做的就是修改參數類型。首先新建一個函數,接收一個字元串參數:
public static Employee Create(string name) { try { var namespaceStr = MethodBase.GetCurrentMethod().DeclaringType.Namespace; var t = Type.GetType(namespaceStr + "." + name); return Activator.CreateInstance(t) as Employee; } catch (Exception ex) { throw new ArgumentException("unable to instantiate " + name); } }
然後修改調用者,將下列這樣的語句:
Employee eng = Employee.Create(Employee.ENGINEER);
修改為:
Employee eng = Employee.Create("Engineer");
修改完後,可以將那個“Create()函數int版”移除了。
現在,當需要添加新的Employee子類時,就不需要再更新Create()函數了。但是卻失去了編譯期檢驗,使得一個小小的拼寫錯誤就可能造成運行期錯誤。如果有必要防止運行期錯誤,則使用明確函數來創建對象(見下個例子)。但這樣一來,每添加一個子類,就必須添加一個新函數。這就是為了類型安全而犧牲掉的靈活性。
範例:以明確函數創建子類
如果只有少數幾個子類,而且它們都不再變化,以明確函數隱藏子類很有用。假如有個Person類,它有兩個子類:Male和Female。首先在基類中為每個子類定義一個工廠函數:
class Person { public static Person CreateMale() { return new Male(); } public static Person CreateFemale() { return new Female(); } }
然後,可以把下麵的調用:
Person kent = new Male();
替換成:
Person kent = Person.CreateMale();
小結
工廠函數是簡單工廠模式的核心函數,實現了對象創建和使用的分離。
To Be Continued……