客户程序需要某一种颜色的时候,只需要创建对应的具体类的实例就可以了。但是这样我们并没有达到封装变化点的目的,也许你会说,可以使用工厂方法模式,为每一个具体子类定义一个与其等级平行的工厂类,那么好,看一下实现:public abstract class Color { public abstract void Display(); } public class RedColor:Color { public override void Display() { Console.WriteLine("Red's RGB Values are:255,0,0"); } } public class GreenColor:Color { public override void Display() { Console.WriteLine("Green's RGB Values are:0,255,0"); } }
实现代码:
实现了这一步之后,可以看到,客户程序只要调用工厂方法就可以了。似乎我们用工厂方法模式来解决是没有问题的。但是,我们考虑的仅仅是封装了new变化,而没有考虑颜色的数量是不断变化的,甚至可能是在程序运行的过程中动态增加和减少的,那么用这种方法实现,随着颜色数量的不断增加,子类的数量会迅速膨大,导致子类过多,显然用工厂方法模式有些不大合适。public abstract class ColorFactory { public abstract Color Create(); } public class RedFactory:ColorFactory { public override Color Create() { return new RedColor(); } } public class GreenFactory:ColorFactory { public override Color Create() { return new GreenColor(); } }
进一步思考,这些Color子类仅仅在初始化的颜色对象类别上有所不同。添加一个ColorTool这样的类,来参数化的它的实例,而这些实例是由Color支持和创建的。我们让ColorTool通过克隆或者拷贝一个Color子类的实例来创建新的Color,这个实例就是一个原型。如下图所示:
实现代码:
现在我们分析一下,这样带来了什么好处?首先从子类的数目上大大减少了,不需要再为每一种具体的颜色产品而定一个类和与它等级平行的工厂方法类,而ColorTool则扮演了原型管理器的角色。再看一下为客户程序的实现:abstract class ColorPrototype { public abstract ColorPrototype Clone(); } class ConcteteColorPrototype : ColorPrototype { private int _red, _green, _blue; public ConcteteColorPrototype(int red, int green, int blue) { this._red = red; this._green = green; this._blue = blue; } public override ColorPrototype Clone() { //实现浅拷贝 return (ColorPrototype) this.MemberwiseClone(); } public void Display(string _colorname) { Console.WriteLine("{0}'s RGB Values are: {1},{2},{3}", _colorname,_red, _green, _blue ); } } class ColorManager { Hashtable colors = new Hashtable(); public ColorPrototype this[string name] { get { return (ColorPrototype)colors[name]; } set { colors.Add(name,value); } } }
class App { public static void Main(string[] args) { ColorManager colormanager = new ColorManager(); //初始化颜色 colormanager["red"] = new ConcteteColorPrototype(255, 0, 0); colormanager["green"] = new ConcteteColorPrototype(0, 255, 0); colormanager["blue"] = new ConcteteColorPrototype(0, 0, 255); colormanager["angry"] = new ConcteteColorPrototype(255, 54, 0); colormanager["peace"] = new ConcteteColorPrototype(128, 211, 128); colormanager["flame"] = new ConcteteColorPrototype(211, 34, 20); //使用颜色 string colorName = "red"; ConcteteColorPrototype c1 = (ConcteteColorPrototype)colormanager[colorName].Clone(); c1.Display(colorName); colorName = "peace"; ConcteteColorPrototype c2 = (ConcteteColorPrototype)colormanager[colorName].Clone(); c2.Display(colorName); colorName = "flame"; ConcteteColorPrototype c3 = (ConcteteColorPrototype)colormanager[colorName].Clone(); c3.Display(colorName); Console.ReadLine(); } }