设计模式:原型模式(Prototype Pattern)

定义:

    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
  Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

    当在程序中确定了所需要的通用类,但需要将具体类延迟到运行时才能确定时,原型模式是另一种可以使用的工具。原型模式与生成器模式的相似之处是,都由莫个类明确定组成最终类的部件或者细节;不同之处在于,原型模式中目标类的构建是通过克隆一个或者多个原型类,然后按预期的行为更改或者补充被克隆类的细节而实现的。

    当你需要的类在他们提供的处理方式上存在不同时,就可以使用原型模式,例如,在分析以不同进制数表示的字符串时。我们考虑一个例子,前面提到的游泳选手比赛问题,假设需要根据不同规则对选手排序,如果每次都生成一个新的实例对系统资源会占用很高。

C#中的克隆

  克隆方法出现在C#中的唯一地方是在ADO DataSet处理里面。我们创建一个DataSet作为数据库查询的结果,其行指针可以一次移动一行。如果出于某种原因,需要把索引保持在DataSet的两个位置上,就需要两个索引。C#处理这个问题最简单的方法就是克隆Dataset。

DataSet cloneDS = ds.Clone();

使用原型模式

    还以游泳选手排序为例看一下原型模式。先定义Swimmer类

        /// <summary>
        /// 游泳者
        /// </summary>
        public class Swimmer:IComparable //需要对选手排序,继承该接口
        {
            private string name;
            private int age;
            public Swimmer(string name, int age)
            {
               this.name = name;
               this.age = age;
            }

            public string GetName()
            {
                return name;
            }

            #region IComparable 成员

            public int CompareTo(object obj)
            {
                Swimmer sw = obj as Swimmer;
                return this.name.CompareTo(sw.name);
            }

            #endregion
        }

 下面我们创建一个SwimData类,它包含数据库读取的Swimmer对象的ArrayList。

View Code
        public class SwimData:ICloneable
{
protected ArrayList swdata;
private int index;

public SwimData(ArrayList list)
{
swdata = list;
this.index = 0;
}

public void MoveFirst()
{
this.index = 0;
}

public bool hasMoreElements()
{
return index < swdata.Count ;
}

public void Sort()
{
swdata.Sort(0, swdata.Count, null);
}

public object Clone()
{
return this.MemberwiseClone();
}

public Swimmer getSwimmer()
{
if (index < swdata.Count )
{
return swdata[index++] as Swimmer;
}
else
return null;
}

}

下面再加一个初始化数据的方法。

View Code
        private void Init()
{
ArrayList list = new ArrayList();
list.Add(new Swimmer("name5", 25));
list.Add(new Swimmer("name6", 26));
list.Add(new Swimmer("name7", 27));
list.Add(new Swimmer("name8", 28));
list.Add(new Swimmer("name0", 20));
list.Add(new Swimmer("name1", 21));
list.Add(new Swimmer("name2", 22));
list.Add(new Swimmer("name3", 23));
list.Add(new Swimmer("name4", 24));

list.Add(new Swimmer("name9", 29));

data = new SwimData(list);
data.MoveFirst();
while (data.hasMoreElements())
{
Swimmer sw = data.getSwimmer();
listBox1.Items.Add(sw.GetName());
}


}

运行程序,如下图

点击“->”按钮对选手排序,然后添加到右侧列表中

View Code
        private void button1_Click(object sender, EventArgs e)
{
listBox2.Items.Clear();
SwimData sd = data.Clone() as SwimData;
sd.Sort();
sd.MoveFirst();
while (sd.hasMoreElements())
{
Swimmer sw = sd.getSwimmer();
listBox2.Items.Add(sw.GetName());
}

DataSet ds = new DataSet();
ds = ds.Clone();
}

结果如下图:

当再次点击“<-”按钮把数据填充回去的时候,发现左侧也别排序了

View Code
        private void button2_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
data.MoveFirst();
while (data.hasMoreElements())
{
Swimmer sw = data.getSwimmer();
listBox1.Items.Add(sw.GetName());
}
}

为什么会这样那? 看我们的Swim实现了ICloneable接口,this.MemberwiseClone() 是浅copy,只复制了引用,没有复制对象本身。所以对新类的所以操作都会反应到新类里面。这时我们主要到,如果再创建一个新类还要集成ICloneable接口,实现clone方法,这是一个不太令人满意的地方,更好的解决方案是,取消让每个类都实现clone方法的接口,把这个处理过程改为让每个类=接受类克隆发送类中的数据。下面给出SwimData类修改部分

View Code
            public void CloneMe(SwimData data)

{

swdata = new ArrayList();

ArrayList swd = data.getData();

for (int i = 0; i < swd.Count; i++)

{

swdata.Add(swd[i]);

}

}


使用对象:
    “某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

原型模式的效果

    用原型模式能根据需要克隆类,这样,在运行时就可以添加或者删除类。根据程序运行情况,可以在运行时更改一个类的内部数据表示,也可以在运行是指定一个新对象而无需创建一个新类。

    用C#实施原型模式的困难在于:如果类早已存在,则不能改变他们来增加需要的克隆方法。另外,间接引用其他类的类也不能别真正克隆。最后,Copy原型类型的想法意味着,你对类中的数据或者方法有足够的访问权限,这样在克隆之后可以修改他们。这可能需要向原型类中添加数据访问方法,这样在克隆之后就能修改数据。

创建型模式小结

1、工厂模式(Factory Pattern)  根据提供工厂的数据,从一系列相关的类中选择一个类实例并且返回。

2、抽象工厂模式(Abstract Factory Pattern)  用于返回一组类中的一个,在某些情况下,他实际上为一组类返回了一个工厂。

3、生成器模式(Builder Pattern)  根据提供给他的数据及其表示,将一系列对象组装成一个新对象。通常选择何种方式组装对象由工厂决定。

    当创建新实例代价比较高的时候,原型模式(Portotype Pattern)拷贝或者克隆一个现有的类,而不是创建一个新实例。

    单件模式(Singleton Pattern)可以保证有且只有一个对象实例,并提供一个该实例的全局访问点。

———————————————————————————————————————— 

 一个人的时候,总是在想

    我的生活到底在期待什么……

原文地址:https://www.cnblogs.com/freeton/p/2281383.html