原型设计模式用在当需要经常使用非常相似的对象的情况下,当需要相似的对象时,原型模式会克隆原始对象并且只修改不同的地方,这样会消耗更少的资源。
代码:
1 abstract class ColorPrototype 2 { 3 4 public abstract ColorPrototype Clone(); 5 } 6 class ConcteteColorPrototype : ColorPrototype 7 { 8 9 private int _red, _green, _blue; 10 11 public ConcteteColorPrototype(int red, int green, int blue) 12 13 { 14 15 this._red = red; 16 17 this._green = green; 18 19 this._blue = blue; 20 21 } 22 23 public override ColorPrototype Clone() 24 25 { 26 27 //实现浅拷贝 28 29 return (ColorPrototype) this.MemberwiseClone(); 30 31 } 32 33 public void Display(string _colorname) 34 35 { 36 37 Console.WriteLine("{0}'s RGB Values are: {1},{2},{3}", 38 39 _colorname,_red, _green, _blue ); 40 41 } 42 } 43 class ColorManager 44 { 45 46 47 Hashtable colors = new Hashtable(); 48 49 50 51 public ColorPrototype this[string name] 52 53 { 54 55 get 56 57 { 58 59 return (ColorPrototype)colors[name]; 60 61 } 62 63 set 64 65 { 66 67 colors.Add(name,value); 68 69 } 70 71 } 72 }
现在我们分析一下,这样带来了什么好处?首先从子类的数目上大大减少了,不需要再为每一种具体的颜色产品而定一个类和与它等级平行的工厂方法类,而ColorTool则扮演了原型管理器的角色。再看一下为客户程序的实现:
1 class App 2 { 3 4 public static void Main(string[] args) 5 6 { 7 8 ColorManager colormanager = new ColorManager(); 9 10 //初始化颜色 11 12 colormanager["red"] = new ConcteteColorPrototype(255, 0, 0); 13 14 colormanager["green"] = new ConcteteColorPrototype(0, 255, 0); 15 16 colormanager["blue"] = new ConcteteColorPrototype(0, 0, 255); 17 18 colormanager["angry"] = new ConcteteColorPrototype(255, 54, 0); 19 20 colormanager["peace"] = new ConcteteColorPrototype(128, 211, 128); 21 22 colormanager["flame"] = new ConcteteColorPrototype(211, 34, 20); 23 24 //使用颜色 25 26 string colorName = "red"; 27 28 ConcteteColorPrototype c1 = (ConcteteColorPrototype)colormanager[colorName].Clone(); 29 30 c1.Display(colorName); 31 32 colorName = "peace"; 33 34 ConcteteColorPrototype c2 = (ConcteteColorPrototype)colormanager[colorName].Clone(); 35 36 c2.Display(colorName); 37 38 colorName = "flame"; 39 40 ConcteteColorPrototype c3 = (ConcteteColorPrototype)colormanager[colorName].Clone(); 41 42 c3.Display(colorName); 43 44 Console.ReadLine(); 45 46 } 47 }
可以看到,客户程序通过注册原型实例就可以将一个具体产品类并入到系统中,在运行时刻,可以动态的建立和删除原型。最后还要注意一点,在上面的例子中,用的是浅表复制。如果想做深复制,需要通过序列化的方式来实现。经过了上面的分析之后,我们再来思考下面的问题:
1.为什么需要Prototype模式?
引入原型模式的本质在于利用已有的一个原型对象,快速的生成和原型对象一样的实例。你有一个A的实例a:A a = new A();现在你想生成和car1一样的一个实例b,按照原型模式,应该是这样:A b = a.Clone();而不是重新再new一个A对象。通过上面这句话就可以得到一个和a一样的实例,确切的说,应该是它们的数据成员是一样的。Prototype模式同样是返回了一个A对象而没有使用new操作。
2.引入Prototype模式带来了什么好处?
可以看到,引入Prototype模式后我们不再需要一个与具体产品等级结构平行的工厂方法类,减少了类的构造,同时客户程序可以在运行时刻建立和删除原型。
3.Prototype模式满足了哪些面向对象的设计原则?
依赖倒置原则:上面的例子,原型管理器(ColorManager)仅仅依赖于抽象部分(ColorPrototype),而具体实现细节(ConcteteColorPrototype)则依赖与抽象部分(ColorPrototype),所以Prototype很好的满足了依赖倒置原则。
通过序列化实现深拷贝
要实现深拷贝,可以通过序列化的方式。抽象类及具体类都必须标注为可序列化的[Serializable],上面的例子加上深拷贝之后的完整程序如下:
1 using System; 2 using System.Collections; 3 using System.IO; 4 using System.Runtime.Serialization; 5 using System.Runtime.Serialization.Formatters.Binary; 6 [Serializable] 7 abstract class ColorPrototype 8 { 9 10 public abstract ColorPrototype Clone(bool Deep); 11 } 12 [Serializable] 13 class ConcteteColorPrototype : ColorPrototype 14 { 15 16 private int _red, _green, _blue; 17 18 public ConcteteColorPrototype(int red, int green, int blue) 19 20 { 21 22 this._red = red; 23 24 this._green = green; 25 26 this._blue = blue; 27 28 } 29 30 public override ColorPrototype Clone(bool Deep) 31 32 { 33 34 if(Deep) 35 36 return CreateDeepCopy(); 37 38 else 39 40 return (ColorPrototype) this.MemberwiseClone(); 41 42 } 43 44 45 46 //实现深拷贝 47 48 public ColorPrototype CreateDeepCopy() 49 50 { 51 52 ColorPrototype colorPrototype; 53 54 MemoryStream memoryStream = new MemoryStream(); 55 56 BinaryFormatter formatter = new BinaryFormatter(); 57 58 formatter.Serialize(memoryStream, this); 59 60 memoryStream.Position = 0; 61 62 63 64 colorPrototype = (ColorPrototype)formatter.Deserialize(memoryStream); 65 66 return colorPrototype; 67 68 } 69 70 71 72 public ConcteteColorPrototype Create(int red,int green,int blue) 73 74 { 75 76 77 return new ConcteteColorPrototype(red,green,blue); 78 79 80 } 81 82 public void Display(string _colorname) 83 84 { 85 86 Console.WriteLine("{0}'s RGB Values are: {1},{2},{3}", 87 88 _colorname,_red, _green, _blue ); 89 90 } 91 } 92 class ColorManager 93 { 94 95 96 Hashtable colors = new Hashtable(); 97 98 public ColorPrototype this[string name] 99 100 { 101 102 get 103 104 { 105 106 return (ColorPrototype)colors[name]; 107 108 } 109 110 set 111 112 { 113 114 colors.Add(name,value); 115 116 } 117 118 } 119 } 120 class App 121 { 122 123 public static void Main(string[] args) 124 125 { 126 127 ColorManager colormanager = new ColorManager(); 128 129 //初始化颜色 130 131 colormanager["red"] = new ConcteteColorPrototype(255, 0, 0); 132 133 colormanager["green"] = new ConcteteColorPrototype(0, 255, 0); 134 135 colormanager["blue"] = new ConcteteColorPrototype(0, 0, 255); 136 137 colormanager["angry"] = new ConcteteColorPrototype(255, 54, 0); 138 139 colormanager["peace"] = new ConcteteColorPrototype(128, 211, 128); 140 141 colormanager["flame"] = new ConcteteColorPrototype(211, 34, 20); 142 143 //使用颜色 144 145 string colorName = "red"; 146 147 ConcteteColorPrototype c1 = (ConcteteColorPrototype)colormanager[colorName].Clone(false); 148 149 c1.Display(colorName); 150 151 colorName = "peace"; 152 153 ConcteteColorPrototype c2 = (ConcteteColorPrototype)colormanager[colorName].Clone(true); 154 155 c2.Display(colorName); 156 157 colorName = "flame"; 158 159 ConcteteColorPrototype c3 = (ConcteteColorPrototype)colormanager[colorName].Clone(true); 160 161 c3.Display(colorName); 162 163 Console.ReadLine(); 164 165 } 166 }
实现要点
1.使用原型管理器,体现在一个系统中原型数目不固定时,可以动态的创建和销毁,如上面的举的调色板的例子。
2.实现克隆操作,在.NET中可以使用Object类的MemberwiseClone()方法来实现对象的浅表拷贝或通过序列化的方式来实现深拷贝。
3.Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有稳定的接口。
效果
1.它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。
2.Prototype模式允许客户只通过注册原型实例就可以将一个具体产品类并入到系统中,客户可以在运行时刻建立和删除原型。
3.减少了子类构造,Prototype模式是克隆一个原型而不是请求工厂方法创建一个,所以它不需要一个与具体产品类平行的Creater类层次。
4.Portotype模式具有给一个应用软件动态加载新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响老系统。
5.产品类不需要非得有任何事先确定的等级结构,因为Prototype模式适用于任何的等级结构
6.Prototype模式的最主要缺点就是每一个类必须配备一个克隆方法。而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。
适用性
在下列情况下,应当使用Prototype模式:
1.当一个系统应该独立于它的产品创建,构成和表示时;
2.当要实例化的类是在运行时刻指定时,例如,通过动态装载;
3.为了避免创建一个与产品类层次平行的工厂类层次时;
4.当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
总结
Prototype模式同工厂模式,同样对客户隐藏了对象的创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的,达到了“隔离类对象的使用者和具体类型(易变类)之间的耦合关系”的目的。
(本文转自:http://bbs.51aspx.com/showtopic-43421.html)