原型模式

什麼是原型模式?

原型模式是一種對象建立型模式,它將一個原型對象傳遞給一個要發起建立的對象,該對象經過請求原型對象複製本身來實現建立過程。編程

因爲軟件系統中常常會出現須要建立多個相同或類似的對象,所以原型模式在開發中具備較高的使用頻率。經過原型模式克隆出來的對象屬於全新的對象,它們在內存中擁有本身的內存地址,對克隆對象的修改不會影響原型對象,而且每個克隆對象都是相互獨立的。網絡

淺克隆與深克隆

淺克隆

在淺克隆中,若是原型對象的成員變量是值類型,將會複製一份給克隆對象;若是成員變量是引用類型,則將引用類型的地址複製一份給克隆對象,也就是說克隆對象與原型對象的成員變量指向相同的內存地址。即淺克隆的時候,只複製原型對象自己和它的值類型成員,而引用類型的成員並無複製。ide

深克隆

深克隆的時候,原型對象中的值類型成員和引用類型成員都將複製給克隆對象,即深克隆除了複製對象自己之外,對象所包含的全部成員也將被複制。this

原型模式的結構

image.png

  • ProtoType(抽象原型類):聲明克隆方法的接口,全部具體原型類的父類,能夠是抽象類或者接口。
  • ProtoTypeA(具體原型類):繼承自ProtoType並實現克隆方法,在克隆方法中返回一個本身的克隆對象。
  • Client(使用類):使用的時候讓一個原型對象克隆自身建立一個新的對象,只須要建立出一個原型對象,就能夠經過調用原型對象的克隆方法便可獲得多個相同的對象。

原型模式的實現

abstract class ProtoType
{
    public abstract ProtoType Clone();
}

class ProtoTypeA : ProtoType
{
    private string m_Attr;
    public string Attr
    {
        get
        {
            return this.m_Attr;
        }

        set
        {
            this.m_Attr = value;
        }
    }
    
    public override ProtoType Clone()
    {
        var o = new ProtoTypeA();
        o.Attr = this.m_Attr;
        return o;
    }
}

static void Main()
{
    //使用
    var prototypeA = new ProtoTypeA();
    var copy = prototypeA.Clone();
}

C#的MemberwiseClone方法

在C#語言中,提供了MemberwiseClone方法用於實現淺克隆,修改代碼以下:spa

class ProtoTypeA : ProtoType
{
    private string m_Attr;
    public string Attr
    {
        get
        {
            return this.m_Attr;
        }

        set
        {
            this.m_Attr = value;
        }
    }
    
    private Member m_Member;
    public Member Member
    {
        get
        {
            return this.m_Member;
        }

        set
        {
            this.m_Member = value;
        }
    }
        
    public override ProtoType Clone()
    {
        return (ProtoTypeA)this.MemberwiseClone();
    }
}

調用如下代碼證實爲淺克隆

static void Main()
{
    var prototypeA = new ProtoTypeA();
    var copy = (ProtoTypeA)prototypeA.Clone();
    Console.WriteLine(prototypeA == copy); //false
    Console.WriteLine(prototypeA.Attr == copy.Attr); //true
    Console.WriteLine(prototypeA.Member == copy.Member); //true,證實爲淺克隆
    Console.ReadKey();
}

修改代碼實現深克隆

public override ProtoType Clone()
{
    var copy = (ProtoTypeA)this.MemberwiseClone();
    copy.Member = new Member();
    return copy;
}

static void Main()
{
    var prototypeA = new ProtoTypeA();
    var copy = (ProtoTypeA)prototypeA.Clone();
    Console.WriteLine(prototypeA == copy); //false
    Console.WriteLine(prototypeA.Attr == copy.Attr); //true
    Console.WriteLine(prototypeA.Member == copy.Member); //false,證實爲深克隆
    Console.ReadKey();
}

序列化實現深克隆

[Serializable]
abstract class ProtoType
{
    public abstract ProtoType Clone();
}
    
[Serializable]
class Member { }

[Serializable]
class ProtoTypeA : ProtoType
{
    ...
}

修改Clone方法

public override ProtoType Clone()
{
    ProtoTypeA copy = null;
    using (var fs = new FileStream("Temp.txt", FileMode.Create))
    {
        try
        {
            new BinaryFormatter().Serialize(fs, this);
        }
        catch (SerializationException e)
        {

            throw e;
        }
    }

    using (var fs = new FileStream("Temp.txt", FileMode.Open))
    {
        try
        {
            copy = (ProtoTypeA)new BinaryFormatter().Deserialize(fs);
        }
        catch (SerializationException e)
        {

            throw e;
        }
    };
    return copy;
}

static void Main()
{
    var prototypeA = new ProtoTypeA();
    prototypeA.Member = new Member();
    var copy = (ProtoTypeA)prototypeA.Clone();
    Console.WriteLine(prototypeA == copy); //false
    Console.WriteLine(prototypeA.Attr == copy.Attr); //true
    Console.WriteLine(prototypeA.Member == copy.Member); //false,證實爲深克隆
    Console.ReadKey();
}

原型模式的優勢&缺點

優勢

  • 若是要建立的對象實例較爲複雜,使用原型模式能夠簡化對象的建立過程,提升新實例的建立效率。
  • 較好的擴展性,原型模式中提供了抽象原型類,針對抽象編程,可將具體原型類寫入配置文件。
  • 簡化了建立結構,與工廠方法模式不一樣,無需專門的工廠類來建立對象。
  • 可使用深克隆的方法保存對象的狀態,使用原型模式將對象複製一份並將其狀態保存,以便在須要用的時候使用,例如恢復到某一歷史狀態。

缺點

  • 實現深克隆時須要編寫較爲複雜的代碼,當對象之間存在多重嵌套引用時,每一層對象都必須支持深克隆,實現起來會比較麻煩,增長系統理解難度。

適合使用原型模式的場景

  • 建立對象成本較大(耗時長、佔用CPU資源或網絡資源大),新對象能夠經過複製已有對象得到,如果類似對象,則能夠修改其成員變量便可。
  • 系統須要保存對象的狀態。
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息