【設計模式】C#設計模式:原型模式

【設計模式】面向對象設計七大原則
【設計模式】設計模式概念和分類
【設計模式】C#設計模式:單例模式
【設計模式】C#設計模式:工廠方法模式
【設計模式】C#設計模式:抽象工廠模式
【設計模式】C#設計模式:建造者模式
【設計模式】C#設計模式:原型模式

原型模式定義

原型模式(Prototype Pattern):是一種對象創建型模式,用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。原型模式允許一個對象再創建另外一個可定製的對象,無須知道任何創建的細節。原型模式的基本工作原理是通過將一個原型對象傳給那個要發動創建的對象,這個要發動創建的對象通過請求原型對象拷貝原型自己來實現創建過程。通過複製一個已經存在的實例來創建一個新的實例。被複制的實例被稱爲原型,這個原型是可定製的。

原型模式結構

抽象原型(Prototype):這是一個抽象角色,通常由一個接口或抽象類實現。此角色給出所有的具體原型類所需的接口。在 C#中,抽象原型角色通常實現了 ICloneable 接口。
具體原型(Concrete Prototype):被複制的對象。此角色需要實現抽象的原型角色所要求的接口。
客戶(Client):客戶端類向原型管理器提出創建對象的請求。
原型管理器(Prototype Manager):創建具體原型類的對象,並記錄每一個被創建的對象。

原型模式分析

在原型模式結構中定義了一個抽象原型類,實現.NET的System命名空間爲我們提供了一個ICloneable接口,它包含了一個方法Clone(),提供該類型的對象的副本,來實現對象的拷貝。

通常情況下,一個類包含一些成員對象,在使用原型模式克隆對象時,根據其成員對象是否也拷貝,原型模式可以分爲兩種形式:深拷貝淺拷貝

ICloneable接口

該接口使你能夠創建現有對象的副本的自定義的實現。該接口只提供了,一個Clone方法,實現對象的淺拷貝。有淺拷貝,那麼就有相對應的深拷貝。但該接口並沒有對我們提供,需要我們自己實現。

淺拷貝

淺拷貝(Shallow Clone):當原型對象被複制時,只複製它本身和其中包含的值類型的成員變量,而引用類型的成員變量並沒有複製。將原來對象中的所有字段逐個複製到一個新對象,如果字段是值類型,則簡單地複製一個副本到新對象,改變新對象的值類型字段不會影響原對象;如果字段是引用類型,則複製的是引用,改變目標對象中引用類型字段的值將會影響原對象。

在C#中調用 MemberwiseClone() 方法即爲淺複製。如果字段是值類型的,則對字段執行逐位複製,如果字段是引用類型的,則複製對象的引用,而不復制對象。

C#中淺拷貝方法介紹:

public class ShallowClone : ICloneable
{
	/// <summary>
	/// 淺克隆
	/// </summary>
	/// <returns></returns>
	public object Clone()
	{
		return this.MemberwiseClone();
	}
}

深拷貝

深拷貝(Deep Clone):除了對象本身被複制外,對象所包含的所有成員變量也將被複制。與淺複製不同之處在於對引用類型的處理,深複製將新對象中引用類型字段指向複製過的新對象,改變新對象中引用的任何對象,不會影響到原來的對象中對應字段的內容。

C#中深拷貝方法介紹:
利用反射實現

public static T DeepCopy<T>(T obj)
{
	//如果是字符串或值類型則直接返回
	if (obj is string || obj.GetType().IsValueType) return obj;
	
	object retval = Activator.CreateInstance(obj.GetType());
	FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
	foreach (FieldInfo field in fields)
	{
		try { field.SetValue(retval, DeepCopy(field.GetValue(obj))); }
		catch { }
	}
	return (T)retval;
}

利用xml序列化和反序列化實現

public static T DeepCopy<T>(T obj)
{
	object retval;
	using (MemoryStream ms = new MemoryStream())
	{
		XmlSerializer xml = new XmlSerializer(typeof(T));
		xml.Serialize(ms, obj);
		ms.Seek(0, SeekOrigin.Begin);
		retval = xml.Deserialize(ms);
		ms.Close();
	}
	return (T)retval;
}

利用二進制序列化和反序列化實現

public static T DeepCopy<T>(T obj)
{
	object retval;
	using (MemoryStream ms = new MemoryStream())
	{
		BinaryFormatter bf = new BinaryFormatter();
		//序列化成流
		bf.Serialize(ms, obj);
		ms.Seek(0, SeekOrigin.Begin);
		//反序列化成對象
		retval = bf.Deserialize(ms);
		ms.Close();
	}
	return (T)retval;
}

原型模式實例

在這裏插入代碼片

原型模式優點

隱藏了對象的創建細節,對有些初始化需要佔用很多資源的類來說,對性能也有很大提高。
在需要新對象時,可以使用Clone來快速創建創建一個,而不用使用new來構建。

原型模式缺點

每一個類都需要一個Clone方法,而且必須通盤考慮。對於深拷貝來說,每個關聯到的類型都不許實現IClonable接口,並且每增加或修改一個字段是都需要更新Clone方法。

原型模式使用場景

(1)類初始化需要消化非常多的資源,這個資源包括數據、硬件資源等
(2)通過new產生一個對象需要非常繁瑣的數據準備或訪問權限,則可以使用原型模式
(3)一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用。
(4)在實際項目中,原型模式很少單獨出現,一般是和工廠模式一起出現,通過Clone方法創建一個對象,然後由工廠方法提供給調用者。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章