程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#設計模式之原型設計模式(Prototype)

C#設計模式之原型設計模式(Prototype)

編輯:關於C#

一、原型(Prototype)模式

原型模式的用意是:通過給出一個原型對象來指明所要創建的對象類型,然後用復制這個原型對象的辦法創建出更多的同類型對象。

從孫大聖的手段談起

孫悟空在與黃風怪的戰斗中,"使一個身外身的手段:把毫毛揪下一把,用口嚼得粉碎,望上一噴,叫聲'變',變有百十個行者,都是一樣得打扮,各執一根鐵棒,把那怪圍在空中。"換而言之,孫悟空可以根據自己的形象,復制出很多"身外身"來。

老孫這種身外身的手段在面向對象設計領域裡叫原型(Prototype)模式。

C#對原型模式的支持

在C#裡面,我們可以很容易的通過Clone()方法實現原型模式。任何類,只要想支持克隆,必須實現C#中的ICloneable接口。ICloneable接口中有一Clone方法,可以在類中復寫實現自定義的克隆方法。克隆的實現方法有兩種:淺拷貝(shallow copy)與深拷貝(deep copy)。

(以下摘自:《.NET框架程序設計(修訂版)》,李建忠譯)淺拷貝是指當對象的字段值被拷貝時,字段引用的對象不會被拷貝。例如,如果一個對象有一個指向字符串的字段,並且我們對該對象做了一個淺拷貝,那麼兩個對象將引用同一個字符串。而深拷貝是對對象實例中字段引用的對象也進行拷貝的一種方式,所以如果一個對象有一個指向字符串的字段,並且我們對該對象做了一個深拷貝的話,我們將創建一個新的對象和一個新的字符串--新對象將引用新字符串。需要注意的是執行深拷貝後,原來的對象和新創建的對象不會共享任何東西;改變一個對象對另外一個對象沒有任何影響。

二、Prototype模式的結構:

客戶(Client)角色:客戶類提出創建對象的請求。

抽象原型(Prototype)角色:這是一個抽象角色,通常由一個C#接口或抽象類實現。此角色給出所有的具體原型類所需的接口。在C#中,抽象原型角色通常實現了ICloneable接口。

具體原型(Concrete Prototype)角色:被復制的對象。此角色需要實現抽象原型角色所要求的接口。

三、程序舉例:

下面的程序給出了一個示意性的實現:

// Prototype pattern -- Structural example 
using System;
// "Prototype"
abstract class Prototype
{
 // Fields
 private string id;
 // Constructors
 public Prototype( string id )
 {
  this.id = id;
 }
 public string Id
 {
  get{ return id; }
 }
 // Methods
 abstract public Prototype Clone();
}
// "ConcretePrototype1"
class ConcretePrototype1 : Prototype
{
 // Constructors
 public ConcretePrototype1( string id ) : base ( id ) {}
 // Methods
 override public Prototype Clone()
 {
  // Shallow copy
  return (Prototype)this.MemberwiseClone();
 }
}
// "ConcretePrototype2"
class ConcretePrototype2 : Prototype
{
 // Constructors
 public ConcretePrototype2( string id ) : base ( id ) {}
 // Methods
 override public Prototype Clone()
 {
  // Shallow copy
  return (Prototype)this.MemberwiseClone();
 }
}
/**//// <summary>
/// Client test
/// </summary>
class Client
{
 public static void Main( string[] args )
 {
  // Create two instances and clone each
  ConcretePrototype1 p1 = new ConcretePrototype1( "I" );
  ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
  Console.WriteLine( "Cloned: {0}", c1.Id );
  ConcretePrototype2 p2 = new ConcretePrototype2( "II" );
  ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
  Console.WriteLine( "Cloned: {0}", c2.Id );
 }
}

這個例子實現了一個淺拷貝。其中MemberwiseClone()方法是Object類的一個受保護方法,實現了對象的淺拷貝。如果希望實現一個深拷貝,應該實現ICloneable接口,並自己編寫ICloneable的Clone接口方法。

四、帶Prototype Manager的原型模式

原型模式的第二種形式是帶原型管理器的原型模式,其UML圖如下:

客戶(Client)角色:客戶端類向原型管理器提出創建對象的請求。

抽象原型(Prototype)角色:這是一個抽象角色,通常由一個C#接口或抽象類實現。此角色給出所有的具體原型類所需的接口。在C#中,抽象原型角色通常實現了ICloneable接口。

具體原型(Concrete Prototype)角色:被復制的對象。此角色需要實現抽象的原型角色所要求的接口。

原型管理器(Prototype Manager)角色:創建具體原型類的對象,並記錄每一個被創建的對象。

下面這個例子演示了在原型管理器中存儲用戶預先定義的顏色原型,客戶通過原型管理器克隆顏色對象。

// Prototype pattern -- Real World example 
using System;
using System.Collections;
// "Prototype"
abstract class ColorPrototype
{
 // Methods
 public abstract ColorPrototype Clone();
}
// "ConcretePrototype"
class Color : ColorPrototype
{
 // Fields
 private int red, green, blue;
 // Constructors
 public Color( int red, int green, int blue)
 {
  this.red = red;
  this.green = green;
  this.blue = blue;
 }
 // Methods
 public override ColorPrototype Clone()
 {
  // Creates a 'shallow copy'
  return (ColorPrototype) this.MemberwiseClone();
 }
 public void Display()
 {
  Console.WriteLine( "RGB values are: {0},{1},{2}",
   red, green, blue );
 }
}
// Prototype manager
class ColorManager
{
 // Fields
 Hashtable colors = new Hashtable();
 // Indexers
 public ColorPrototype this[ string name ]
 {
  get{ return (ColorPrototype)colors[ name ]; }
  set{ colors.Add( name, value ); }
 }
}
/**//// <summary>
/// PrototypeApp test
/// </summary>
class PrototypeApp
{
 public static void Main( string[] args )
 {
  ColorManager colormanager = new ColorManager();
  // Initialize with standard colors
  colormanager[ "red" ] = new Color( 255, 0, 0 );
  colormanager[ "green" ] = new Color( 0, 255, 0 );
  colormanager[ "blue" ] = new Color( 0, 0, 255 );
  // User adds personalized colors
  colormanager[ "angry" ] = new Color( 255, 54, 0 );
  colormanager[ "peace" ] = new Color( 128, 211, 128 );
  colormanager[ "flame" ] = new Color( 211, 34, 20 );
  // User uses selected colors
  string colorName = "red";
  Color c1 = (Color)colormanager[ colorName ].Clone();
  c1.Display();
  colorName = "peace";
  Color c2 = (Color)colormanager[ colorName ].Clone();
  c2.Display();
  colorName = "flame";
  Color c3 = (Color)colormanager[ colorName ].Clone();
  c3.Display();
 }
}

五、淺拷貝與深拷貝

下面給出淺拷貝與深拷貝的兩個例子,例子使用了ICloneable接口。C#中的數組是引用型的變量,我們通過數組來進行演示:

淺拷貝:

using System;
class ShallowCopy : ICloneable
{
 public int[] v = {1,2,3};
 public Object Clone()
 {
  return this.MemberwiseClone();
 }
 public void Display()
 {
  foreach(int i in v)
   Console.Write( i + ", ");
  Console.WriteLine();
 }
}
class Client
{
 public static void Main()
 {
  ShallowCopy sc1 = new ShallowCopy();
  ShallowCopy sc2 = (ShallowCopy)sc1.Clone();
  sc1.v[0] = 9;
  sc1.Display();
  sc2.Display();
 }
}

ShallowCopy對象實現了一個淺拷貝,因此當對sc1進行克隆時,其字段v並沒有克隆,這導致sc1與sc2的字段v都指向了同一個v,因此,當修改了sc1的v[0]後,sc2的v[0]也發生了變化。

深拷貝:

using System;
class DeepCopy : ICloneable
{
 public int[] v = {1,2,3};
 // 默認構造函數
 public DeepCopy()
 {
 }
 // 供Clone方法調用的私有構造函數
 private DeepCopy(int[] v)
 {
  this.v = (int[])v.Clone();
 }
 public Object Clone()
 {
  // 構造一個新的DeepCopy對象,構造參數為
  // 原有對象中使用的 v
  return new DeepCopy(this.v);
 }
 public void Display()
 {
  foreach(int i in v)
   Console.Write( i + ", ");
  Console.WriteLine();
 }
}
class Client
{
 public static void Main()
 {
  DeepCopy dc1 = new DeepCopy();
  DeepCopy dc2 = (DeepCopy)dc1.Clone();
  dc1.v[0] = 9;
  dc1.Display();
  dc2.Display();
 }
}

這次在克隆的時候,不但克隆對象本身,連裡面的數組字段一並克隆。因此,最終打印出來的dc1與dc2不同。

六、Prototype模式的優點與缺點

Prototype模式的優點包括

1、Prototype模式允許動態增加或減少產品類。由於創建產品類實例的方法是產批類內部具有的,因此增加新產品對整個結構沒有影響。

2、Prototype模式提供了簡化的創建結構。工廠方法模式常常需要有一個與產品類等級結構相同的等級結構,而Prototype模式就不需要這樣。

3、Portotype模式具有給一個應用軟件動態加載新功能的能力。由於Prototype的獨立性較高,可以很容易動態加載新功能而不影響老系統。

4、產品類不需要非得有任何事先確定的等級結構,因為Prototype模式適用於任何的等級結構。

Prototype模式的缺點:

Prototype模式的最主要缺點就是每一個類必須配備一個克隆方法。而且這個克隆方法需要對類的功能進行通盤考慮,這對全新的類來說不是很難,但對已有的類進行改造時,不一定是件容易的事。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved