zoukankan      html  css  js  c++  java
  • 我也设计模式——5.Prototype

    我很喜欢这个模式,因为它解决了对象赋值的问题。尤其是那个Clone方法,记忆犹新。

    使用场景:当一个系统应该独立于产品的创建,构成和表示时,使用设计模式。


    .NET提供了ICloneable接口,只要实现了其Clone方法,在其中执行复制对象的操作。关键就是这个Clone方法,由于对象的复杂性,分为浅复制
    和深复制两种:
    对于浅复制,可以使用Object的MembermiseClone方法:
        public class A : ICloneable
        
    {
            
    public object Clone()
            
    {
                
    return this.MemberwiseClone();
            }

        }
    但是,这样复制的对象没有任何区别。于是,可以使用如下折中的办法,
        class Program
        
    {
            
    static void Main()
            
    {
                A a1 
    = new A("bjq");

                A a2 
    = (A)a1.Clone();
                a2.f1 
    = "jax";
            }

        }


        
    public class A : ICloneable
        
    {
            
    public string f1;
            
    public string f2;

            
    public A(string f1)
            
    {
                
    this.f1 = f1;
            }


            
    public object Clone()
            
    {
                A a 
    = new A();
                a.f2 
    = f2;

                
    return a;
            }

        }
    可以看到,对象a2虽然是a1的复制,但f1字段是不一样的。
    ——这里说的不一样,不是具有相同字段/属性值的两个不同指针,我只是想找出两个从外表看有区别的对象。

    对于深复制,要使用序列化来实现Clone方法,从而不仅仅复制对象本身,同时连同被引用的对象一起复制,代码如下:
        [Serializable]
        
    public class A
        
    {
            
    private string f1;
            
    private string f2;

            
    public A(string f1, string f2)
            
    {
                
    this.f1 = f1;
                
    this.f2 = f2;
            }


            
    public A Clone()
            
    {
                MemoryStream memoryStream 
    = new MemoryStream();
                BinaryFormatter formatter 
    = new BinaryFormatter();
                formatter.Serialize(memoryStream, 
    this);
                memoryStream.Position 
    = 0;
                A a 
    = (A)formatter.Deserialize(memoryStream);

                
    return a;
            }

        }

    这里只是说明如何正确使用串行化,而效果并不明显,如果引用一个数组,则能表现出深浅序列化的区别。
    深复制在互相引用时,会陷入死循环:A引用B,B又引用A——对于此,是没有完美的解决方案的,为此,我们可以加一个didClone标记,以减少这种问题。

    案例分析:
    IDE中的ToolBox中各个小工具的实现,比如说Button和TextBox等,可以用原型模式实现。每个Control都要实现Clone()方法,比如说Label:
        public class myLabel : Label, ICloneable
        
    {
            
    public object Clone()
            
    {
                myLabel ml 
    = new myLabel();
                
    return ml;
            }

        }
    于是,在Form中实现如下:
        public partial class Form1 : Form
        
    {
            
    private Hashtable ht = new Hashtable();
            
    private string status = "Label";

            
    private void Form1_Load(object sender, EventArgs e)
            
    {
                MyLabel ml 
    = new MyLabel();
                ml.Text 
    = "Hello";
                ht.Add(
    "Label", ml);
            }


            
    private void button1_Click(object sender, EventArgs e)
            
    {
                ICloneable fc 
    = (ICloneable)ht[status];
                Control c 
    = (Control)fc.Clone();
                
    this.Controls.Add(c);
            }

        }
    我们用 “点击button1按钮” 来模拟 “从ToolBox中拖动Control到Form” 这个功能。这里仅仅实现了Label,我们还可以用同样的方法模拟Button,TreeView等控件。

    案例2,调色板,这个案例参见http://terrylee.cnblogs.com/archive/2006/01/16/317896.html,其思想与案例1是一样的:每次得到的色笔都是一个copy,仅仅是颜色的不同。由于每种颜色由RGB三原色组合搭配而成,所以会有256^3个对象,为此,使用原型模式可以将这个对象减少为1个,可以看成是水彩画中的一支毛笔和RGB三个色盒。

    原型模式可以解决抽象工厂平行子类太多的问题,同样的,Flyweight也可以实现,只是后者更倾向于结构而不关心生成,这时候要使用注册工厂。

    对于DataSet ds:
        ds.Copy()方法,返回ds的结构和数据;
        ds.Clone()方法,返回ds的结构

    原型模式的缺点:
    Prototype模式的最主要缺点就是每一个类必须配备一个克隆方法。而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。

    关于深浅复制的定义:
    浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。
        ——以上摘自CLR框架设计,Array是最好的例证。
  • 相关阅读:
    Confluence 6 连接到一个 LDAP 目录
    Confluence 6 LDAP 成员结构设置
    Confluence 6 LDAP 用户组结构设置
    Confluence 6 LDAP 用户结构设置
    Confluence 6 LDAP 高级设置
    Confluence 6 自动添加用户到用户组
    Confluence 6 权限设置
    一个小白的测试环境docker化之路
    客户端SDK测试思路
    限时购校验小工具&dubbo异步调用实现限
  • 原文地址:https://www.cnblogs.com/Jax/p/716028.html
Copyright © 2011-2022 走看看