設計模式(0)簡單工廠模式 設計模式(1)單例模式(Singleton) 設計模式(2)工廠方法模式(Factory Method) 設計模式(3)抽象工廠模式(Abstract Factory) 設計模式(4)建造者模式/生成器模式(Builder) 源碼地址 0 原型模式簡介 0.0 原型模式定 ...
設計模式(3)抽象工廠模式(Abstract Factory)
0 原型模式簡介
0.0 原型模式定義
原型模式是一種常用的創建型模式,原型模式的一般定義為用原型實例指定創建對象的種類,並通過拷貝這些原型創建新的對象
原型模式要求對象必須具有一個可以“克隆”自身的方法,這樣就可以通過這個克隆自身的方法創建一個新的同一類型的實例。我們通常將這個克隆自身的方法定義在抽象的介面上,直接通過介面調用其內部包含的克隆方法,創建一個具體的對象。這樣就可以實現通過原型模式創建具體對象,無需關註這個對象本身的類型,也不用關心其內部的具體實現,而無須再去通過new去創建具體的類型的實例。
原型模式的結構圖如下
Prototype:聲明一個克隆自身的介面,用來約束想要克隆自身的類,所有想要實現克隆自身這一功能的類需要繼承此介面,並且實現該介面里定義的克隆自身的方法
ConcretePrototype:實現了Prototype介面的具體實現類,這些類中負責Clone這一方法的具體實現
Client:客戶端,通過原型實例克隆自身的Clone方法創建新的對象實例
0.1 原型模式應用場景
在war3中,有一個道具叫做“幻象權杖”其作用是使用後能製造目標單位的一個幻象。我們不考究幻象的其他具體細節,從外形上是與本體完全一摸一樣的。
我們先創建一個英雄的介面
/// <summary> /// 英雄介面定義 /// </summary> public interface IHero { /// <summary> /// 身體特征 /// </summary> string Body { get; set; } /// <summary> /// 武器 /// </summary> string Weapon { get; set; } /// <summary> /// 坐騎 /// </summary> string Mount { get; set; } }
DH類具體實現
/// <summary> /// 惡魔獵手 /// </summary> public class DH : IHero { /// <summary> /// 身體特征 /// </summary> public string Body { get { return "黑夜給了我黑色眼睛,我卻用它去尋找光明。"; } set { } } /// <summary> /// 武器 /// </summary> public string Weapon { get { return "艾辛諾斯雙刃。"; } set { } } /// <summary> /// 坐騎 /// </summary> public string Mount { get { return "我有這雙腳有這雙腿。"; } set { } } }
POM類具體實現
/// <summary> /// 月亮女祭司 /// </summary> public class POM : IHero { /// <summary> /// 身體特征 /// </summary> public string Body { get { return "夜幕只為朱顏改,群星隕落無窮。"; } set { } } /// <summary> /// 武器 /// </summary> public string Weapon { get { return "索利達爾·群星之怒。"; } set { } } /// <summary> /// 坐騎 /// </summary> public string Mount { get { return "艾斯卡達爾。"; } set { } } }
幻象權杖類實現
/// <summary> /// 幻象權杖 /// </summary> public class WandOfIllusion { public static IHero Use(IHero hero) { IHero result = null; if (hero is DH) { result = new DH(); } else if (hero is POM) { result = new POM(); } return result; } }
客戶端使用
class Program { static void Main(string[] args) { DH dh = new DH(); var dh1 = WandOfIllusion.Use(dh); // 對dh使用幻象權杖 Console.ReadLine(); } }
這樣可以實現英雄使用幻象權杖複製自身這一基本需求,但是明顯存在一下問題
1、通過幻象權杖複製英雄對象本身 這一通用的功能代碼中,不應該強依賴具體的英雄類,應該是與具體的實現無關的。
2、難以擴展,要實現其他英雄使用幻象權杖這一操作,就必須修改幻象權杖類,裡面需要增加更多的類型判斷。而且我們這裡只做了簡要的對象創建處理,而實際中各個對象的創建過程是千差萬別的,這樣我們的幻象權杖類就會變得越來越難以維護。
基於問題的出現以及上述對原型模式的介紹,我們可以使用原型模式解決這一問題。
1 原型模式詳解
0、英雄介面增加Clone方法
按照原型模式的要求,我們需要在英雄介面中增加一個Clone方法,所有英雄的具體實現類實現此方法,完成複製英雄的具體細節。
/// <summary> /// 英雄介面定義 /// </summary> public interface IHero { /// <summary> /// 身體特征 /// </summary> string Body { get; set; } /// <summary> /// 武器 /// </summary> string Weapon { get; set; } /// <summary> /// 坐騎 /// </summary> string Mount { get; set; } /// <summary> /// Clone本身介面定義 /// </summary> /// <returns></returns> IHero Clone(); }
1、具體英雄實現類實現Clone方法
/// <summary> /// 惡魔獵手 /// </summary> public class DH : IHero { /// <summary> /// 身體特征 /// </summary> public string Body { get { return "黑夜給了我黑色眼睛,我卻用它去尋找光明。"; } set { } } /// <summary> /// 武器 /// </summary> public string Weapon { get { return "艾辛諾斯雙刃。"; } set { } } /// <summary> /// 坐騎 /// </summary> public string Mount { get { return "我有這雙腳有這雙腿。"; } set { } } /// <summary> /// Clone /// </summary> /// <returns></returns> public IHero Clone() { IHero hero = new DH(); //TODO:進行其他Clone相關操作 return hero; } }
/// <summary> /// 月亮女祭司 /// </summary> public class POM : IHero { /// <summary> /// 身體特征 /// </summary> public string Body { get { return "夜幕只為朱顏改,群星隕落無窮。"; } set { } } /// <summary> /// 武器 /// </summary> public string Weapon { get { return "索利達爾·群星之怒。"; } set { } } /// <summary> /// 坐騎 /// </summary> public string Mount { get { return "艾斯卡達爾。"; } set { } } /// <summary> /// Clone /// </summary> /// <returns></returns> public IHero Clone() { IHero hero = new POM(); //TODO:進行其他Clone相關操作 return hero; } }
2、修改幻象權杖類
/// <summary> /// 幻象權杖 /// </summary> public class WandOfIllusion { public static IHero Use(IHero hero) { IHero result = null; //if (hero is DH) //{ // result = new DH(); //} //else if (hero is POM) //{ // result = new POM(); //} result = hero.Clone(); return result; } }
至此我們的幻象權杖通用類,已經與具體的英雄實現類無關了。
3、淺克隆和深克隆
淺克隆:只克隆值類型的屬性數據
深克隆:除了要複製淺克隆需要複製的值類型屬性數據外,也要複製引用類型的屬性數據。
2 總結
優點
對客戶端調用隱藏具體實現類細節,減少外部調用對具體實現類的依賴
缺點
每個實現類都必須實現Clone方法,尤其在包含引用類型的深克隆時,需要逐級讓所有的引用類型實現Clone