文章出處

原型模式從字面上來看, 可能還不是那么通俗, 通俗點講, 可以說是拷貝模式.

 從拷貝來說, 有完全拷貝, 和不完全拷貝. 就仿佛孫猴子的吹毛生猴, 但是這些小猴子明顯就沒有孫悟空本體厲害, 這種拷貝, 算是淺拷貝吧. 

既然有淺拷貝, 那肯定也是有深拷貝的. 深拷貝就是小猴子與孫悟空本體一樣厲害, 無論是從本事還是從長相, 都是一樣的

一、原型

/// <summary>
/// 原型
/// </summary>
abstract public class Prototype
{
public int Id { get; set; }

public string Name { get; set; }

public List<int> Size = new List<int>();

public Prototype(int id)
{
    this.Id = id;
}

abstract public Prototype Clone();
}

原型上, 我放了一個值類型, 一個字符串, 一個整形集合, 在原型模式下, 我會修改這幾個值, 來觀察克隆之后的變化

 

二、淺拷貝

public class Concrete1 : Prototype
{
    public Concrete1(int id)
        : base(id)
    { }

    public override Prototype Clone()
    {
        return (Prototype)this.MemberwiseClone();
    }
}

測試代碼:

Console.WriteLine("--------------淺拷貝----------------------");
Concrete1 p1 = new Concrete1(1);
p1.Name = "Name";
p1.Size.AddRange(new int[] { 1, 2, 3, 4, 5 });
Concrete1 c1 = (Concrete1)p1.Clone();
Console.WriteLine("Before Concrete1 change");
Console.WriteLine("Cloned : Id - {0}, Name - {1}, Size - {2}", c1.Id, c1.Name, string.Join(",", c1.Size));

Console.WriteLine();
p1.Id = 2;
p1.Name = "p1.Name";
p1.Size.AddRange(new int[] { 6, 7, 8, 9 });

Console.WriteLine("After Concrete1 changed");
Console.WriteLine("Cloned : Id - {0}, Name - {1}, Size - {2}", c1.Id, c1.Name, string.Join(",", c1.Size));

結果:

可以看到, 我在克隆之后, 修改了原型集合的值,  克隆對象也跟著改變了, 說明他們的集合變量指向同一塊堆空間. 

Console.WriteLine("p1.Size == c1.Size, {0}", p1.Size == c1.Size);

有圖有真相.

 

三、深拷貝

public class Concrete2 : Prototype
{
    public Concrete2(int id)
        : base(id)
    { }

    public override Prototype Clone()
    {var jsonStr = JsonConvert.SerializeObject(this);return JsonConvert.DeserializeObject<Concrete2>(jsonStr);
    }
}

測試代碼:

Console.WriteLine("--------------深拷貝----------------------");
Concrete2 p2 = new Concrete2(2);
p2.Name = "Name";
p2.Size.AddRange(new int[] { 1, 2, 3, 4, 5 });
Concrete2 c2 = (Concrete2)p2.Clone();
Console.WriteLine("Before Concrete2 change");
Console.WriteLine("Cloned : Id - {0}, Name - {2}, Size - {2}", c2.Id, c2.Name, string.Join(",", c2.Size));

Console.WriteLine();
p2.Id = 2;
p2.Name = "p2.Name";
p2.Size.AddRange(new int[] { 6, 7, 8, 9 });

Console.WriteLine("After Concrete2 changed");
Console.WriteLine("Cloned : Id - {0}, Name - {2}, Size - {2}", c2.Id, c2.Name, string.Join(",", c2.Size));

Console.WriteLine("p2.Size == c2.Size, {0}", p2.Size == c2.Size);

 結果:

可以看到, 拷貝實體并沒有任何變化, 說明他們已經是兩個獨立的分開的實體. 并沒有共同的變量引用(方法引用除外).

在這里, 我實現深拷貝的方式是通過序列化的方式, 當然還有很多別的方式. 可以自己實現. C#提供的那個克隆方法, 是淺拷貝的實現.

C#有一個接口:ICloneable, 如果不想做成抽象類, 也可以通過這個接口去實現.

 

四、個人應用

就我個人在項目中的應用來看, 最近使用過結構克隆.

Datatble這個變量, 無論是b/s, 還是c/s, 應該都是用過的吧.

它有一個Clone方法, 可以用來克隆表結構和約束, 相當方便, 我不需要再去做一遍繁雜的表結構創建.

 

參考:

大話設計模式

C#設計模式(9)


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()