原型模式,一個深刻淺出,檢驗你對基礎知識瞭解的是否透徹的一個設計模式。html
之因此這樣定義,由於我栽了個跟頭面試
想要吃透原型模式,就得深刻理解 淺拷貝,深拷貝設計模式
想要深刻吃透 淺拷貝,深拷貝ide
咱們就要對 值類型 和 引用類型 有較深的認識函數
若是對 值類型 和 引用類型 有了較深的認識,在GC也至少有必定的修爲了性能
..........我還能繼續這樣寫下去不少,因此有開頭的那句話,原型模式,一個深刻淺出,檢驗你對基礎知識瞭解的是否透徹的一個設計模式。this
對值類型 和 引用類型 的淺薄的 入門,能夠參考 幾年前寫的 面試前的準備---C#知識點回顧----02spa
裏面有一些基礎知識的介紹,能夠做爲了解 淺拷貝 和 深拷貝的鋪墊設計
重點來了,看黑板!!!code
深拷貝:指的是拷貝一個對象時,不只僅把對象的引用進行復制,還把該對象引用的值也一塊兒拷貝。這樣進行深拷貝後的拷貝對象就和源對象互相獨立,其中任何一個對象的改動都不會對另一個對象形成影響。舉個例子,你有一張光盤,你進行了屢次刻錄,產生了第二張,第三者光盤,那這三種光盤是相互獨立的,第一張損壞或第二張損壞,都不會影響到第三張【光盤,會不會暴露年齡啊】。在.NET領域,值對象就是典型的例子,如int, Double以及結構體和枚舉等。具體例子以下所示:
int source = 11; // 值類型賦值內部執行深拷貝 int copy = source; // 對拷貝對象進行賦值不會改變源對象的值 copy = 22;//此時source仍然爲11 // 一樣對源對象賦值也不會改變拷貝對象的值 source = 33;//此時copy 仍然爲22
怎麼實現深拷貝,能夠最原始的一個一個賦值,但也能夠用反射或反序列化方式來實現,因人而異,具體根據具體需求定,尋找代碼最合適的方法
淺拷貝:指的是拷貝一個對象時,僅僅拷貝對象的引用進行拷貝,可是拷貝對象和源對象仍是引用同一份實體。此時,其中一個對象的改變都會影響到另外一個對象。其實咱們本身常常淺拷貝,在家,你是個寶寶的身份,在學校,你是學生的身份,在公司面前,你是職員,但若是你生病了,那麼你全部身份都會生病,全都反應在你這個實體身上。在.NET中引用類型就是一個例子。如類類型。具體例子以下所示:
Person you = new Person() { Info = "You" }; Person schoolP = you; // 淺拷貝 schoolP.Info = "學生"; // 拷貝對象改變Info值 Person familyP = you; familyP.Info = "寶寶"; Person emp = you; emp.Info = "職員"; // 忽然你生病了 you.Info = "生病了"; Console.WriteLine("schoolP.Info: {0};familyP.Info: {1};emp.Info:{2}", schoolP.Info, familyP.Info, emp.Info); Console.Read(); public class Person { public string Info { get; set; } }
重點!!!在C#中,淺拷貝的實現方式很簡單,.NET自身也提供了實現,只須要實現接口 : ICloneable
.NET中值類型默認是深拷貝的,而對於引用類型,默認實現的是淺拷貝。因此對於類中引用類型的屬性改變時,其另外一個對象也會發生改變。當某個類的實例有個字段是值類型,那麼實際該字段會和類的實例保持在同一個地方,即堆上
這次載的跟頭就是在,讓我痛定思痛的記住了,類都是引用類型
有了前面的鋪墊,咱們來看看原型模式
原型模式:用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象
重點再次來臨,2點
1.前半句告訴你原型還得本身建
2.後半句指點你,剩下的對象能夠經過拷貝實現。具體是深拷貝仍是淺拷貝,根據你的需求來定
舉個例子,來品味下原型模式
在 War3 ,魔獸爭霸[再次暴露年齡], 大海龜地圖中有4個點位有野怪,這些野怪組成由 1個大海龜,2個小海龜組成,都是海龜,他們的差異是傷害輸出的不一樣。
咱們來看看怎麼畫這個圖
先定義野怪,由於在地圖中,除了海歸,還有其餘野怪
/// <summary> /// 敵人,野怪 /// </summary> [Serializable] public abstract class Enemy : ICloneable { protected Enemy(Location location, int power, int speed) { Location = location; Power = power; Speed = speed; } /// <summary> /// 出生點位 /// </summary> public Location Location { get; set; } /// <summary> /// 攻擊力[1~10 愈來愈強] /// </summary> public int Power { get; set; } /// <summary> /// 行動速度[1~10 愈來愈快] /// </summary> public int Speed { get; set; } /// <summary> /// 深拷貝 /// </summary> /// <returns></returns> public abstract Enemy DeepClone(); public abstract void Show(); /// <summary> /// 淺拷貝 /// </summary> /// <returns></returns> public object Clone() { return this.MemberwiseClone(); } }
這是出生點位類
/// <summary> /// 出生點位 /// </summary> [Serializable] public class Location { /// <summary> /// 橫座標 /// </summary> public int X; /// <summary> /// 縱座標 /// </summary> public int Y; public Location(int x, int y) { X = x; Y = y; } }
再定義海歸野怪
/// <summary> /// 海龜 /// </summary> [Serializable] public class SeaTurtle : Enemy { public SeaTurtle(Location location, int power, int speed) : base(location, power, speed) { } public override Enemy DeepClone() { MemoryStream memoryStream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); // 序列化成流 formatter.Serialize(memoryStream, this); memoryStream.Position = 0; // 反序列化成對象 SeaTurtle seaTurtle = (SeaTurtle)formatter.Deserialize(memoryStream); return seaTurtle; } public override void Show() { Console.WriteLine("我是海龜,攻擊力:{0},速度:{1},出生點位:{2},{3}", Power, Speed, Location.X, Location.Y); } }
好比咱們如今要生成一組野怪,咱們看看怎麼用原型模式實現
static void Main() { Location seaTurtleLocation = new Location(2, 2); //大海龜出生 SeaTurtle bigSeaTurtle = new SeaTurtle(seaTurtleLocation, 10, 10); //照着大海龜 拷貝一個小海龜 A Enemy smallSeaTurtleA = (SeaTurtle)bigSeaTurtle.DeepClone(); smallSeaTurtleA.Location.X = seaTurtleLocation.X + 1; smallSeaTurtleA.Power = bigSeaTurtle.Power / 2; //再直接copy小海龜A 拷貝一個小海龜 B Enemy smallSeaTurtleB = (SeaTurtle)smallSeaTurtleA.DeepClone(); smallSeaTurtleB.Location.X = seaTurtleLocation.X - 1; bigSeaTurtle.Show(); smallSeaTurtleA.Show(); smallSeaTurtleB.Show(); Console.ReadLine(); }
最終的結果
我是海龜,攻擊力:10,速度:10,出生點位:2,2 我是海龜,攻擊力:5,速度:10,出生點位:3,2 我是海龜,攻擊力:5,速度:10,出生點位:1,2
我在Enemy類中實現了接口ICloneable,你們能夠試試用Clone方法會獲得什麼效果
總結下
優勢:
用於建立重複的對象,同時又能保證性能,同時,咱們還能夠不用構造方法
缺點
一、配備克隆方法須要對類的功能進行通盤考慮,這對於全新的類不是很難,但對於已有的類不必定很容易,特別當一個類引用不支持串行化的間接對象,或者引用含有循環結構的時候。
二、逃避了構造函數的約束,若是咱們的構造方法有約定,那由於能夠不用到構造方法,因此咱們逃避了約定
以上就是關於 原型模式 的分享
大家的支持是我寫做的動力源泉,請不要吝嗇你的點贊,謝謝