原型模式 :Prototype(转自阿良.NET)
2008-12-03 11:34
459 查看
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。
从孙大圣的手段谈起
孙悟空在与黄风怪的战斗中,"使一个身外身的手段:把毫毛揪下一把,用口嚼得粉碎,望上一喷,叫声'变',变有百十个行者,都是一样得打扮,各执一根铁棒,把那怪围在空中。"换而言之,孙悟空可以根据自己的形象,复制出很多"身外身"来。
老孙这种身外身的手段在面向对象设计领域里叫原型(Prototype)模式。
C#对原型模式的支持
在C#里面,我们可以很容易的通过Clone()方法实现原型模式。任何类,只要想支持克隆,必须实现C#中的ICloneable接口。ICloneable接口中有一Clone方法,可以在类中复写实现自定义的克隆方法。克隆的实现方法有两种:浅拷贝(shallow copy)与深拷贝(deep copy)。
(以下摘自:《.NET框架程序设计(修订版)》,李建忠译)浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。
二、 Prototype模式的结构:
客户(Client)角色:客户类提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个C#接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色通常实现了ICloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象原型角色所要求的接口。
三、 程序举例:
下面的程序给出了一个示意性的实现:
这个例子实现了一个浅拷贝。其中MemberwiseClone()方法是Object类的一个受保护方法,实现了对象的浅拷贝。如果希望实现一个深拷贝,应该实现ICloneable接口,并自己编写ICloneable的Clone接口方法。
四、 带Prototype Manager的原型模式
原型模式的第二种形式是带原型管理器的原型模式,其UML图如下:
客户(Client)角色:客户端类向原型管理器提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个C#接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色通常实现了ICloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。
下面这个例子演示了在原型管理器中存储用户预先定义的颜色原型,客户通过原型管理器克隆颜色对象。
五、 浅拷贝与深拷贝
下面给出浅拷贝与深拷贝的两个例子,例子使用了ICloneable接口。C#中的数组是引用型的变量,我们通过数组来进行演示:
浅拷贝:
ShallowCopy对象实现了一个浅拷贝,因此当对sc1进行克隆时,其字段v并没有克隆,这导致sc1与sc2的字段v都指向了同一个v,因此,当修改了sc1的v[0]后,sc2的v[0]也发生了变化。
深拷贝:
这次在克隆的时候,不但克隆对象本身,连里面的数组字段一并克隆。因此,最终打印出来的dc1与dc2不同。
六、 Prototype模式的优点与缺点
Prototype模式的优点包括
1、Prototype模式允许动态增加或减少产品类。由于创建产品类实例的方法是产批类内部具有的,因此增加新产品对整个结构没有影响。
2、Prototype模式提供了简化的创建结构。工厂方法模式常常需要有一个与产品类等级结构相同的等级结构,而Prototype模式就不需要这样。
3、Portotype模式具有给一个应用软件动态加载新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响老系统。
4、产品类不需要非得有任何事先确定的等级结构,因为Prototype模式适用于任何的等级结构。
Prototype模式的缺点:
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 [/b]using[/b] System; // "Prototype" [/b]abstract[/b] class[/b] Prototype { // Fields [/b] private[/b] string[/b] id; // Constructors [/b] public[/b] Prototype( string[/b] id ) { this[/b].id = id; } public[/b] string[/b] Id { get[/b]{ return[/b] id; } } // Methods [/b] abstract[/b] public[/b] Prototype Clone(); } // "ConcretePrototype1" [/b]class[/b] ConcretePrototype1 : Prototype { // Constructors [/b] public[/b] ConcretePrototype1( string[/b] id ) : base[/b] ( id ) {} // Methods [/b] override[/b] public[/b] Prototype Clone() { // Shallow copy [/b] return[/b] (Prototype)this[/b].MemberwiseClone(); } } // "ConcretePrototype2" [/b]class[/b] ConcretePrototype2 : Prototype { // Constructors [/b] public[/b] ConcretePrototype2( string[/b] id ) : base[/b] ( id ) {} // Methods [/b] override[/b] public[/b] Prototype Clone() { // Shallow copy [/b] return[/b] (Prototype)this[/b].MemberwiseClone(); } } /**/[/b]/// <summary> /// Client test [/b]/// </summary> [/b]class[/b] Client { public[/b] static[/b] void[/b] Main( string[/b][] args ) { // Create two instances and clone each [/b] ConcretePrototype1 p1 = new[/b] ConcretePrototype1( "I"[/b] ); ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone(); Console.WriteLine( "Cloned: {0}"[/b], c1.Id ); ConcretePrototype2 p2 = new[/b] ConcretePrototype2( "II"[/b] ); ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone(); Console.WriteLine( "Cloned: {0}"[/b], c2.Id ); } }
这个例子实现了一个浅拷贝。其中MemberwiseClone()方法是Object类的一个受保护方法,实现了对象的浅拷贝。如果希望实现一个深拷贝,应该实现ICloneable接口,并自己编写ICloneable的Clone接口方法。
四、 带Prototype Manager的原型模式
原型模式的第二种形式是带原型管理器的原型模式,其UML图如下:
客户(Client)角色:客户端类向原型管理器提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个C#接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色通常实现了ICloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。
下面这个例子演示了在原型管理器中存储用户预先定义的颜色原型,客户通过原型管理器克隆颜色对象。
// Prototype pattern -- Real World example [/b]using[/b] System; using[/b] System.Collections; // "Prototype" [/b]abstract[/b] class[/b] ColorPrototype { // Methods [/b] public[/b] abstract[/b] ColorPrototype Clone(); } // "ConcretePrototype" [/b]class[/b] Color : ColorPrototype { // Fields [/b] private[/b] int[/b] red, green, blue; // Constructors [/b] public[/b] Color( int[/b] red, int[/b] green, int[/b] blue) { this[/b].red = red; this[/b].green = green; this[/b].blue = blue; } // Methods [/b] public[/b] override[/b] ColorPrototype Clone() { // Creates a 'shallow copy' [/b] return[/b] (ColorPrototype) this[/b].MemberwiseClone(); } public[/b] void[/b] Display() { Console.WriteLine( "RGB values are: {0},{1},{2}"[/b], red, green, blue ); } } // Prototype manager [/b]class[/b] ColorManager { // Fields [/b] Hashtable colors = new[/b] Hashtable(); // Indexers [/b] public[/b] ColorPrototype this[/b][ string[/b] name ] { get[/b]{ return[/b] (ColorPrototype)colors[ name ]; } set[/b]{ colors.Add( name, value ); } } } /**/[/b]/// <summary> /// PrototypeApp test [/b]/// </summary> [/b]class[/b] PrototypeApp { public[/b] static[/b] void[/b] Main( string[/b][] args ) { ColorManager colormanager = new[/b] ColorManager(); // Initialize with standard colors [/b] colormanager[ "red"[/b] ] = new[/b] Color( 255, 0, 0 ); colormanager[ "green"[/b] ] = new[/b] Color( 0, 255, 0 ); colormanager[ "blue"[/b] ] = new[/b] Color( 0, 0, 255 ); // User adds personalized colors [/b] colormanager[ "angry"[/b] ] = new[/b] Color( 255, 54, 0 ); colormanager[ "peace"[/b] ] = new[/b] Color( 128, 211, 128 ); colormanager[ "flame"[/b] ] = new[/b] Color( 211, 34, 20 ); // User uses selected colors [/b] string[/b] colorName = "red"[/b]; Color c1 = (Color)colormanager[ colorName ].Clone(); c1.Display(); colorName = "peace"[/b]; Color c2 = (Color)colormanager[ colorName ].Clone(); c2.Display(); colorName = "flame"[/b]; Color c3 = (Color)colormanager[ colorName ].Clone(); c3.Display(); } }
五、 浅拷贝与深拷贝
下面给出浅拷贝与深拷贝的两个例子,例子使用了ICloneable接口。C#中的数组是引用型的变量,我们通过数组来进行演示:
浅拷贝:
using[/b] System; class[/b] ShallowCopy : ICloneable { public[/b] int[/b][] v = {1,2,3}; public[/b] Object Clone() { return[/b] this[/b].MemberwiseClone(); } public[/b] void[/b] Display() { foreach[/b](int[/b] i in[/b] v) Console.Write( i + ", "[/b]); Console.WriteLine(); } } class[/b] Client { public[/b] static[/b] void[/b] Main() { ShallowCopy sc1 = new[/b] 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[/b] System; class[/b] DeepCopy : ICloneable { public[/b] int[/b][] v = {1,2,3}; // 默认构造函数 [/b] public[/b] DeepCopy() { } // 供Clone方法调用的私有构造函数 [/b] private[/b] DeepCopy(int[/b][] v) { this[/b].v = (int[/b][])v.Clone(); } public[/b] Object Clone() { // 构造一个新的DeepCopy对象,构造参数为 [/b] // 原有对象中使用的 v [/b] return[/b] new[/b] DeepCopy(this[/b].v); } public[/b] void[/b] Display() { foreach[/b](int[/b] i in[/b] v) Console.Write( i + ", "[/b]); Console.WriteLine(); } } class[/b] Client { public[/b] static[/b] void[/b] Main() { DeepCopy dc1 = new[/b] 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模式的最主要缺点就是每一个类必须配备一个克隆方法。而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。
相关文章推荐
- 设计模式--原型模式(Prototype)
- 2.6 《硬啃设计模式》第8章 复制不是很难 - 原型模式(Prototype Pattern)
- 设计模式(五)----- 原型模式(Prototype)----(JAVA版)
- 【Unity与23种设计模式】原型模式(Prototype)
- 设计模式学习总结4 - 创建型4 - Prototype原型模式
- HeadFirst 设计模式学习笔记19--原型(Prototype)模式拾零
- 设计模式之原型模式(Prototype)
- C++设计模式之九--Prototype原型模式
- 设计模式--Prototype原型模式
- C#面向对象设计模式纵横谈 笔记6 Prototype 原型(创建型模式)
- Prototype - 原型创建模式
- 原型模式Prototype
- c++设计模式之原型模式Prototype
- Net设计模式实例之原型模式( Prototype Pattern)
- 原型模式:Prototype
- 跟着实例学习设计模式(7)-原型模式prototype(创建型)
- 设计模式之原型模式(Prototype)摘录
- 设计模式之原型模式(prototype)
- 原型(prototype)模式
- Java设计模式 创建模式-原型模式(Prototype)