在軟體系統中,當建立一個類的執行個體的過程很昂貴或很複雜,并且我們需要建立多個這樣類的執行個體時,如果我們用new操作符去建立這樣的類執行個體,這未免會增加建立類的複雜度和耗費更多的記憶體空間,因為這樣在記憶體中配置設定了多個一樣的類執行個體對象,然後如果采用工廠模式來建立這樣的系統的話,随着産品類的不斷增加,導緻子類的數量不斷增多,反而增加了系統複雜程度,是以在這裡使用工廠模式來封裝類建立過程并不合适,然而原型模式可以很好地解決這個問題,因為每個類執行個體都是相同的,當我們需要多個相同的類執行個體時,沒必要每次都使用new運算符去建立相同的類執行個體對象,此時我們一般思路就是想——隻建立一個類執行個體對象,如果後面需要更多這樣的執行個體,可以通過對原來對象拷貝一份來完成建立,這樣在記憶體中不需要建立多個相同的類執行個體,進而減少記憶體的消耗和達到類執行個體的複用。 然而這個思路正是原型模式的實作方式。下面就具體介紹下設計模式中的原型設計模式。
在現實生活中,也有很多原型設計模式的例子,例如,細胞分裂的過程,一個細胞的有絲分裂産生兩個相同的細胞;還有西遊記中孫悟空變出後孫的本領和火影忍者中鳴人的隐分身忍術等。下面就以孫悟空為例子來示範下原型模式的實作。具體的實作代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<code>///火影忍者中鳴人的影分身和孫悟空的的變都是原型模式</code>
<code> </code><code>class</code> <code>Client</code>
<code> </code><code>{</code>
<code> </code><code>static</code> <code>void</code> <code>Main(</code><code>string</code><code>[] args)</code>
<code> </code><code>{</code>
<code> </code><code>// 孫悟空 原型</code>
<code> </code><code>MonkeyKingPrototype prototypeMonkeyKing = </code><code>new</code> <code>ConcretePrototype(</code><code>"MonkeyKing"</code><code>);</code>
<code> </code><code>// 變一個</code>
<code> </code><code>MonkeyKingPrototype cloneMonkeyKing = prototypeMonkeyKing.Clone() </code><code>as</code> <code>ConcretePrototype;</code>
<code> </code><code>Console.WriteLine(</code><code>"Cloned1:\t"</code><code>+cloneMonkeyKing.Id);</code>
<code> </code><code>// 變兩個</code>
<code> </code><code>MonkeyKingPrototype cloneMonkeyKing2 = prototypeMonkeyKing.Clone() </code><code>as</code> <code>ConcretePrototype;</code>
<code> </code><code>Console.WriteLine(</code><code>"Cloned2:\t"</code> <code>+ cloneMonkeyKing2.Id);</code>
<code> </code><code>Console.ReadLine();</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>/// <summary></code>
<code> </code><code>/// 孫悟空原型</code>
<code> </code><code>/// </summary></code>
<code> </code><code>public</code> <code>abstract</code> <code>class</code> <code>MonkeyKingPrototype</code>
<code> </code><code>public</code> <code>string</code> <code>Id { </code><code>get</code><code>; </code><code>set</code><code>; }</code>
<code> </code><code>public</code> <code>MonkeyKingPrototype(</code><code>string</code> <code>id)</code>
<code> </code><code>this</code><code>.Id = id;</code>
<code> </code><code>// 克隆方法,即孫大聖說“變”</code>
<code> </code><code>public</code> <code>abstract</code> <code>MonkeyKingPrototype Clone();</code>
<code> </code><code>/// 建立具體原型</code>
<code> </code><code>public</code> <code>class</code> <code>ConcretePrototype : MonkeyKingPrototype</code>
<code> </code><code>public</code> <code>ConcretePrototype(</code><code>string</code> <code>id)</code>
<code> </code><code>: </code><code>base</code><code>(id)</code>
<code> </code><code>{ }</code>
<code> </code><code>/// <summary></code>
<code> </code><code>/// 淺拷貝</code>
<code> </code><code>/// </summary></code>
<code> </code><code>/// <returns></returns></code>
<code> </code><code>public</code> <code>override</code> <code>MonkeyKingPrototype Clone()</code>
<code> </code><code>// 調用MemberwiseClone方法實作的是淺拷貝,另外還有深拷貝</code>
<code> </code><code>return</code> <code>(MonkeyKingPrototype)</code><code>this</code><code>.MemberwiseClone();</code>
上面原型模式的運作結果為(從運作結果可以看出,建立的兩個拷貝對象的ID屬性都是與原型對象ID屬性一樣的):

上面代碼實作的淺拷貝的方式,淺拷貝是指當對象的字段值被拷貝時,字段引用的對象不會被拷貝。例如,如果一個對象有一個指向字元串的字段,并且我們對該對象做了一個淺拷貝,那麼這兩個對象将引用同一個字元串,而深拷貝是對對象執行個體中字段引用的對象也進行拷貝,如果一個對象有一個指向字元串的字段,并且我們對該對象進行了深拷貝的話,那麼我們将建立一個對象和一個新的字元串,新的對象将引用新的字元串。也就是說,執行深拷貝建立的新對象和原來對象不會共享任何東西,改變一個對象對另外一個對象沒有任何影響,而執行淺拷貝建立的新對象與原來對象共享成員,改變一個對象,另外一個對象的成員也會改變。
介紹完原型模式的實作代碼之後,下面看下原型模式的類圖,通過類圖來理清原型模式實作中類之間的關系。具體類圖如下:
原型模式的優點有:
原型模式向客戶隐藏了建立新執行個體的複雜性
原型模式允許動态增加或較少産品類。
原型模式簡化了執行個體的建立結構,工廠方法模式需要有一個與産品類等級結構相同的等級結構,而原型模式不需要這樣。
産品類不需要事先确定産品的等級結構,因為原型模式适用于任何的等級結構
原型模式的缺點有:
每個類必須配備一個克隆方法
配備克隆方法需要對類的功能進行通盤考慮,這對于全新的類不是很難,但對于已有的類不一定很容易,特别當一個類引用不支援串行化的間接對象,或者引用含有循環結構的時候。
在.NET中可以很容易地通過實作ICloneable接口(這個接口就是原型,提供克隆方法,相當于與上面代碼中MonkeyKingPrototype抽象類)中Clone()方法來實作原型模式,如果我們想我們自定義的類具有克隆的功能,首先定義類繼承與ICloneable接口并實作Clone方法。在.NET中實作了原型模式的類如下圖所示(圖中隻截取了部分,可以用Reflector反編譯工具進行檢視):
到這裡關于原型模式的介紹就結束了,原型模式用一個原型對象來指明所要建立的對象類型,然後用複制這個原型對象的方法來建立出更多的同類型對象,它與工廠方法模式的實作非常相似,其中原型模式中的Clone方法就類似工廠方法模式中的工廠方法,隻是工廠方法模式的工廠方法是通過new運算符重新建立一個新的對象(相當于原型模式的深拷貝實作),而原型模式是通過調用MemberwiseClone方法來對原來對象進行拷貝,也就是複制,同時在原型模式優點中也介紹了與工廠方法的差別(第三點)。
<a href="http://down.51cto.com/data/2363531" target="_blank">附件:http://down.51cto.com/data/2363531</a>
本文轉自LearningHard 51CTO部落格,原文連結:http://blog.51cto.com/learninghard/1299687,如需轉載請自行聯系原作者