l

2016年4月7日 星期四

用Replace Type Code with Subclasses移除Primitive Obsession怪味道

March 28 11:10~11:57

螢幕截圖 2016-03-28 11.56.24

 

▼Primitive Obsession怪味道經常出現在switch case裡面,做為判斷case的條件(type code)。下圖為HardDrive類別,它有一個int _type變數用來紀錄硬碟的種類(SATA、SAS、SCSI、USB),它的smartCheck()函數依據_type變數判斷採用何種方式來執行硬碟檢查。

螢幕截圖 2016-03-28 11.31.14

***

▼要把這個switch case拿掉,可以套用Replace Type Code with Subclasses重構,顧名思義就是將每一條switch case用一個subclass來取代。如下所示,先將HardDriver改成abstract class,讓它的子類別覆寫smartCheck()函數。

螢幕截圖 2016-03-28 11.37.21

 

▼以SATA類別為例,把與原本在switch case裡面呼叫doSATASmartCheck()的程式碼搬移到SATA類別的smartCheck()函數。注意到了嗎,smartCheck()函數已經沒有switch case了。其他三個類別SAS、SCSI、USB的修改方式也類似。

螢幕截圖 2016-03-28 11.42.20

 

▼重構前後的測試案例差異不大,因為主要是把smartCheck()內部的switch case拿掉,對客戶端的影響只有在HardDrive身上多了一個factory method,透過它來產生HardDriver的不同子類別。

螢幕截圖 2016-03-28 11.46.42

 

▼重構後。

螢幕截圖 2016-03-28 11.48.41

 

***

友藏內心獨白:Factory method裡面也有switch case啊XD。

1 則留言:

  1. 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()));
    }

    回覆刪除