第十二课 原型模式

第十二课 原型模式

       定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

      上面就是原型模式的定义了。那么为什么我们要采用原型模式呢?设想一下,现在有这么一个东西,其实可以把它抽象出一个类,但是由于他属性有着千变万化,而每种变化可能都是我们所需要的。那么解决方案呢?我想大家能马上想到以下方式:

1.    在使用的时候初始化不同属性。

2.    使用类似工厂模式的方法,把每个变化作为一个产品。通过工厂生产产品。

3.    使用建造者模式,建造不同属性的对象出来。

 

首先看 1 这种方法(估计大家都这么办的,别砸我哦),他直接在使用的时候进行初始化,我说这种方式不可取,每次都要初始化不同信息,耦合性高不说,垃圾代码也多,不符合咱们设计模式的原则。

然后看 2 这种方法(在了解原型前,大家最容易想到的方法,其实能想到已经不错了)。工厂方法确实可以解决问题,但是,由于变化过多,可能导致工厂类过多,并不适合在这里使用。

再看 3 这种方法。刚讲完了建造者方法,想用也是正常的。这里用来初始化属性看着也没错,但是同样的,需要多少建造方法呀。变化是动态产生的,每种变化都要一个吗?

 

这里就引出原型模式了。像这种产品类是动态变化的,但是其实可以进一步抽象出来相同点,转变为同一对象不同属性这种方式(个人理解,有待商榷)。这时就可以考虑使用原型模式。

下面引用一个例子。(在李会军博客看到的,我稍微进行了下改进。主要是使用了配置的方式初始化管理对象)

 

      下面采用示例来说明。现在要实现一个假调色板,上面有个种颜色可以选定。一般看到这里都会想到,把Color这个对象抽象出来吧。就像下面代码:

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");

   }

}

好的,这样我们有了红和绿两种颜色了。下面怎么处理,我要封装变化啊。工厂方法好像可以哦,那么我用工厂来实现。

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();

   }

}

 

确实好像工厂方法能够完美的封装变化进去。但是我如果想要添加yellow?blue?你说了,我只要实现相应的产品类,然后实现相应的工厂方法。。。。。。发现问题了吧,颜色那么多,需要多少子类啊!!!

这里再仔细想想我上面说的,能够抽象出一个对象Color,不同颜色也只是具体属性不同是吧?其实就是初始化的值不同呗?那么不正好用原型模式吗。(个人理解)

下面就是原型方式的实现:

using System;

using System.Collections;

using System.Collections.Generic;

using System.Text;

using System.IO;

namespace 原型模式

{

    public class ColorSample

    {

        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();

 

        }

 

 

    }

 

    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 ColorManager()

        {

          

            StreamReader fs = new StreamReader(File.OpenRead("ColorConfig.txt"));

            string str = "";

            char[] sp = {','};

            while (true)

            {

                str = fs.ReadLine();

                if (string.IsNullOrEmpty(str))

                    break;

                string[] colorinfo = str.Split(sp);

 

                colors[colorinfo[0]] = new ConcteteColorPrototype(

                    int.Parse(colorinfo[1]),

                    int.Parse(colorinfo[2]),

                    int.Parse(colorinfo[3])

                    );

 

            }

           

        }

 

 

        public ColorPrototype this[string name]

        {

 

            get

            {

 

                return (ColorPrototype)colors[name];

 

            }

 

            set

            {

 

                colors.Add(name, value);

 

            }

 

        }

 

    }

 

}

这里我使用了读取配置文件的方式初始化原型管理类,配置文件如下

red,255,0,0

green,0,255,0

blue,0,0,255

angry,255,54,0

peace,128,211,128

flame,211,34,20

比较懒,没使用XML,直接用的csv文件。

下面切入正题。(想尝试先看代码后分析的方法)

原型模式的实现方法如下图所示。

 

所谓原型,就是实现将多个对象初始化。然后在需要对象的时候,通过Clone()方法(喜欢交Copy()也随你),获得已经初始化好的对象的副本。从而实现快速获得对象的方式。在实际应用中,多数采取通过一个Manager对象的方法来管理原型对象。如下图。

 

ColorTool就是一个Manager(管理)类,用来管理所有的原型对象。

好了,现在大概也了解了原型模式的实现方法了。来套示例代码吧。

首先,ColorPrototype 就是原型对象了,其实一般应用时多直接使用 ICloneable (.net) , Cloneable Java)直接作为Clone()接口哦。

然后ConcteteColorPrototype 就是真正的抽象出来的对象了。这里就是颜色对象。里面定义了RGB3个参数,其实参数不同,就是不同颜色(表告诉我不知道RGB)。

再来看管理类ColorManager ,其实就是图中的ColorTool,它里面定义了一个HashTable,用来存放已经设定的原型对象。使用索引属性的方式来设定和取得原型对象。

这里大家抛去构造函数外,就是李会军博客里的示例。主函数里面注释掉的,就是原始用法。围绕着这里进行过深入讨论,具体请看:

http://www.cnblogs.com/Terrylee/archive/2006/01/16/317896.html

 

我这里做了下处理,通过配置文件的方式初始化了一下所有的原型对象。这样规避了里面提到的一些问题。其实正如李会军博客里面说的,不要指望一个设计模式解决所有问题。模式是为了解决问题,只要能方便用,怎么处理不好。

呵呵,废话完了,坐下总结。

 

原型模式,说白了就是先创建一个对象,把他初始化,然后再需要同样对象的时候,直接通过.clone()方法,获得这个对象的副本。从而省去了初始化等等操作。方便获得现成对象。

 

补充一下。示例ConcteteColorPrototype中的Clone()方法是用的浅表复制。相对应的,还有深拷贝方法。一般是通过序列化对象方式进行复制。区别是什么呢?一般类中很可能定义有引用类型的属性对吧,浅拷贝中,相同引用属性,指向的是相同对象,也就是说,修改浅拷贝对象的引用属性,会影响到原型的引用属性。而深拷贝不同,他会完全副本所有属性,可以放心使用。但是相对的,操作消耗的资源也大,使用的时候需要衡量一下。下面给出支持2中覆盖的源码。

using System;

using System.Collections;

using System.Collections.Generic;

using System.Text;

using System.IO;

using System.Runtime.Serialization;

 

using System.Runtime.Serialization.Formatters.Binary;

 

 

 

 

namespace 原型模式

{

    public class ColorSample

    {

        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(true);

 

            c1.Display(colorName);

 

 

            colorName = "peace";

 

            ConcteteColorPrototype c2 = (ConcteteColorPrototype)colormanager[colorName].Clone(false);

 

            c2.Display(colorName);

 

 

            colorName = "flame";

 

            ConcteteColorPrototype c3 = (ConcteteColorPrototype)colormanager[colorName].Clone(true);

 

            c3.Display(colorName);

 

 

            Console.ReadLine();

 

        }

 

 

    }

    [Serializable]

    abstract class ColorPrototype

    {

 

        public abstract ColorPrototype Clone(bool deep);

 

    }

 

    [Serializable]

    class ConcteteColorPrototype : ColorPrototype

    {

 

 

        private int _red, _green, _blue;

 

        public override ColorPrototype Clone(bool Deep)

        {

 

            if (Deep)

 

                return CreateDeepCopy();

 

            else

 

                return (ColorPrototype)this.MemberwiseClone();

 

        }

 

 

        //实现深拷贝

 

        public ColorPrototype CreateDeepCopy()

        {

 

            ColorPrototype colorPrototype;

 

 

            MemoryStream memoryStream = new MemoryStream();

 

            BinaryFormatter formatter = new BinaryFormatter();

 

 

            formatter.Serialize(memoryStream, this);

 

            memoryStream.Position = 0;

 

 

            colorPrototype = (ColorPrototype)formatter.Deserialize(memoryStream);

 

            return colorPrototype;

 

        }

 

 

        public ConcteteColorPrototype Create(int red, int green, int blue)

        {

 

            return new ConcteteColorPrototype(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 ColorManager()

        {

          

            StreamReader fs = new StreamReader(File.OpenRead("ColorConfig.txt"));

            string str = "";

            char[] sp = {','};

            while (true)

            {

                str = fs.ReadLine();

                if (string.IsNullOrEmpty(str))

                    break;

                string[] colorinfo = str.Split(sp);

 

                colors[colorinfo[0]] = new ConcteteColorPrototype(

                    int.Parse(colorinfo[1]),

                    int.Parse(colorinfo[2]),

                    int.Parse(colorinfo[3])

                    );

 

            }

            

        }

 

 

        public ColorPrototype this[string name]

        {

 

            get

            {

 

                return (ColorPrototype)colors[name];

 

            }

 

            set

            {

 

                colors.Add(name, value);

 

            }

 

        }

 

    }

 

}

好了,这一课就到这里吧。对了,12月初有个日语二级考试,最近可能需要复习一下,而且最近领导抓一些事情,可能更新速度会有所降低。(其实主要我也要现学再卖,呵呵)大家见谅。

 

作者:王文斌

转载请注明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值