zoukankan      html  css  js  c++  java
  • 设计模式:原型模式(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)可以保证有且只有一个对象实例,并提供一个该实例的全局访问点。

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

     一个人的时候,总是在想

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

  • 相关阅读:
    java json 库之 jackson
    java 多线程
    golang slice 和 string 重用
    golang 字节对齐
    golang 并发编程之生产者消费者
    golang 设计模式之选项模式
    golang aws-sdk-go 之 s3 服务
    markdown 一个优雅的写作工具
    常见句型、用法
    hg
  • 原文地址:https://www.cnblogs.com/freeton/p/2281383.html
Copyright © 2011-2022 走看看