.Net Framework源代碼中的模式之Prototype(原型模式)
用原型實例指定創建對象的種類,并且通過拷貝這個原型來創建新的對象。
以.NET Framework 2.0 System.Collections中類為例。
System.Collections. ICollection
{
}
System.Collections. ICloneable
{
object Clone();
}
System.Collections. Stack
{
public virtual Object Clone()
{
Stack s = new Stack(_size);
s._size = _size;
Array.Copy(_array, 0, s._array, 0, _size);
s._version = _version;
return s;
}
}
System.Collections. Queue
{
public virtual Object Clone()
{
Queue q = new Queue(_size);
q._size = _size;
int numToCopy = _size;
int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;
Array.Copy(_array, _head, q._array, 0, firstPart);
numToCopy -= firstPart;
if (numToCopy > 0)
Array.Copy(_array, 0, q._array, _array.Length - _head, numToCopy);
q._version = _version;
return q;
}
}
調用代碼
{
public static void Main()
{
Stack myStack = new Stack();
myStack.Push("Hello");
myStack.Push("World");
myStack.Push("!");
Stack myStackCopy = (Stack)myStack.Clone();
foreach (string s in myStackCopy)
{
Console.Write(s);
}
Console.WriteLine();
Console.ReadLine();
}
}
在.NET Framework中,可以通過實現ICloneable接口來實現原型模式,ICloneable接口只有一個Clone方法。克隆的實現方法有兩種:淺拷貝(shallow copy)與深拷貝(deep copy)。
淺拷貝是指當對象的字段值被拷貝時,字段引用的對象不會被拷貝。例如,如果一個對象有一個指向字符串的字段,并且我們對該對象做了一個淺拷貝,那么兩個對象將引用同一個字符串。而深拷貝是對對象實例中字段引用的對象也進行拷貝的一種方式,所以如果一個對象有一個指向字符串的字段,并且我們對該對象做了一個深拷貝的話,我們將創建一個新的對象和一個新的字符串--新對象將引用新字符串。需要注意的是執行深拷貝后,原來的對象和新創建的對象不會共享任何東西;改變一個對象對另外一個對象沒有任何影響。
對于值類型,淺拷貝通過賦值等操作直接實現,將對象中的值類型的字段拷貝到新的對象中;深拷貝和淺拷貝相同,通過賦值等操作直接實現,將對象中的值類型的字段拷貝到新的對象中。 對于引用類型,淺拷貝通過MemberwiseClone 方法創建一個淺副本,方法是創建一個新對象,如果字段是值類型的,則對該字段執行逐位復制,如果字段是引用類型,則復制引用原始對象,與原對象引用同一對象;深拷貝拷貝對象應用,也拷貝對象實際內容,也就是創建了一個新的對象,改變新對象不會影響到原始對象的內容。
在下列情況下,應當使用Prototype模式:
- 當一個系統應該獨立于它的產品創建,構成和表示時;
- 當要實例化的類是在運行時刻指定時,例如,通過動態裝載;
- 為了避免創建一個與產品類層次平行的工廠類層次時;
- 當一個類的實例只能有幾個不同狀態組合中的一種時。建立相應數目的原型并克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。