跟著專案學設計模式(五):簡單工廠+單例模式+靜態類+延遲載入
接上文,專案交付之後,我們的類庫開發人員發現自己穿越了,回到【設計模式——2、簡單工廠模式】這篇文章所在時間線的最末尾。
由於穿越所造成的蝴蝶效應,這個專案後期雖然確實需要擴充套件,但是隻是要增加五到六個產品類,並要求儘快交付,以便將關注點放到其他更有價值的專案中去,那趕快來擴充我們的簡單工廠吧。
public class Factory { /// <summary> /// 靜態方法建立Product例項 /// </summary> public static IProduct CreateProduct(string name) { switch(name) { case "USER":return new UserDal();break; case "GOODS":return new GoodsDal();break; case "HISTORY":return new HistoryDal();break; ... } } }
程式碼很快寫完了,測試通過,但是下一步sonar程式碼質量檢測,在工廠類的CreateProduct方法裡卻發現兩個問題,
第一是return和break那裡有壞味道,也是,都已經return了,還怎麼break?(好吧,是我強行這麼寫只是為了推薦一下sonar),那就改成switch裡用變數賦值,最後再return那個變數吧。
第二是方法圈複雜度剛好超過10了,這個扎心了,沒法解決,重構吧!
基本思路:用字典代替switch分支
//工廠類 public class Factory { public static readonly Dictionary<string, IProduct> dictionary = new Dictionary<string, IProduct>() { { "USER", new UserDal() }, { "GOODS", new GoodsDal() }, { "HISTORY", new HistoryDal() }, ... }; /// <summary> /// 靜態方法建立Product例項 /// </summary> public static IProduct CreateProduct(string name) { return dictionary[name]; } }
現在圈複雜度的問題徹底解決了,我們通過靜態常量dictionary和靜態方法CreateProduct實現的,唯一的缺點是在第一次呼叫Factory的時候,會把所有物件建立一次,要知道這可是單層架構,所有的初始化工作都在裡面了,效能何在?加入Lazy<T>延遲載入後能很好地解決這個問題!
//工廠類 public class Factory { public static readonly Dictionary<string, Lazy<IProduct>> dictionary = new Dictionary<string, Lazy<IProduct>>() { { "USER", new Lazy<IProduct>(() => new UserDal(), true) }, { "GOODS", new Lazy<IProduct>(() => new GoodsDal(), true) }, { "HISTORY", new Lazy<IProduct>(() => new HistoryDal(), true) }, ... }; /// <summary> /// 靜態方法建立Product例項 /// </summary> public static IProduct CreateProduct(string name) { return dictionary[name].Value; } }
現在產品物件只會在第一次呼叫的時候建立,而不是呼叫Factory的時候全部建立。
繼續來看,專案組覺得這個方案很有價值,要求以後用到簡單工廠的專案都這樣幹。做法就是所有的簡單工廠類必須去實現ISampleFactory這個介面。
public interface ISampleFactory
{
Dictionary<string, Lazy<IProduct>> Products { get; set; }
IProduct CreateProduct(string name);
}
前面通過靜態常量和靜態方法做的工作,隨著介面的出現,全部作廢了。因為靜態和介面是宿敵了,一個是面向過程的方法集合,一個是面向物件的高階面向介面。接口裡定義的屬性和方法只有物件才能呼叫,而靜態類壓根就沒有物件。
實現介面的類不能是靜態的,類所實現的屬性和方法也不能是靜態的,所以靜態用不了,而且Products也從常量變成了屬性。
靜態被否定了,也只能用單例模式了。我們可以把Dictionary<string, Lazy<IProduct>> Products這個欄位的初始化放到私有建構函式裡,而單例模式只有一個例項,不就意味著Products只會被初始化1次嘍。
//工廠類
public class Factory : ISampleFactory
{
private static Factory instance;//靜態例項
private Factory()
{
Products = new Dictionary<string, Lazy<IProduct>>
{
{ "USER", new Lazy<IProduct>(() => new UserDal(), true) },
{ "GOODS", new Lazy<IProduct>(() => new GoodsDal(), true) },
{ "HISTORY", new Lazy<IProduct>(() => new HistoryDal(), true) },
...
};
}
public static Factory GetInstance()//方法,方法中去例項化類.
{
if (instance == null)
{
instance = new Factory();
}
return instance;
}
public Dictionary<string, Lazy<IProduct>> Products { get; set; }
IProduct ISampleFactory.CreateProduct(string name)
{
return Products[name].Value;
}
}
好了,運用單例模式完美的解決了介面與靜態的矛盾,單例模式真的是非常給力的設計模式。
待續。。。