March 28 11:10~11:57
▼Primitive Obsession怪味道經常出現在switch case裡面,做為判斷case的條件(type code)。下圖為HardDrive類別,它有一個int _type變數用來紀錄硬碟的種類(SATA、SAS、SCSI、USB),它的smartCheck()函數依據_type變數判斷採用何種方式來執行硬碟檢查。
***
▼要把這個switch case拿掉,可以套用Replace Type Code with Subclasses重構,顧名思義就是將每一條switch case用一個subclass來取代。如下所示,先將HardDriver改成abstract class,讓它的子類別覆寫smartCheck()函數。
▼以SATA類別為例,把與原本在switch case裡面呼叫doSATASmartCheck()的程式碼搬移到SATA類別的smartCheck()函數。注意到了嗎,smartCheck()函數已經沒有switch case了。其他三個類別SAS、SCSI、USB的修改方式也類似。
▼重構前後的測試案例差異不大,因為主要是把smartCheck()內部的switch case拿掉,對客戶端的影響只有在HardDrive身上多了一個factory method,透過它來產生HardDriver的不同子類別。
▼重構後。
***
友藏內心獨白:Factory method裡面也有switch case啊XD。
Factory裡用了Switch也限定了這工廠只有四個產品,沒有發揮物件導向的精隨呀,重構成subclass還是聞起來怪怪的。
回覆刪除HardDrive.Create改一下做法
1.利用Assembly.GetExecutingAssembly()取得目前組件,或是Assembly.Load(string filePath)另一個組件。
Assembly assembly = Assembly.Load(filePath);
2.再用此assembly instance的GetType(string className)取得Type,
Type classType = assembly.GetType("IDE");//字串要加Namespace
3.然後用Activator.CreateInstance(Type type)強轉型為HardDrive
HardDrive ide = (HardDrive)Activator.CreateInstance(classType);
4.就可以動態的new出用字串定義且繼承於HardDrive的物件。
工廠若是用這方法產生物件的話,根本不需要用到Switch,最後只要如下,就可以動態產生HardDrive的子子孫孫。
HardDrive ide = HardDrive.Create("IDE",@"D:\HardDrive\ide.dll");//字串要加Namespace
重構後:
string[] hds = new string[]{"USB","SATA","SAS","SCSI","IDE"};
foreach(string s in hds){
HardDrive hd = HardDrive.Create(s,@"D:\thisAssembly.exe");
Console.Write(string.Format("{0} check result={1}",s,hd.smartCheck()));
}