• 浅谈原型模式


          近期菜鸟D在看《大话设计模式》,看到原型模式,有一点自己的想法,所以就记下来。

          老规矩,解释定义:

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

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

          由于感觉光看书不动手实践一下有点不靠谱,就按着自己的理解写了段代码,情景参照《大话设计模式》第9章,简历的复制。

    代码如下:

    //原型类实现接口ICloneable
    public class Prototype : ICloneable
        {
    
            public string ID { get; private set; }
    
            public string Exp { get; set; }
    
            private Company company = new Company();
    
            public Prototype(string id)
            {
                ID = id;
            }
    
            public void SetExp(string exp)
            {
                Exp = exp;
            }
    
            #region 引用类型的拷贝
    
            //SetCompany是浅拷贝
            public void SetCompany(string address)
            {
                company.Address = address;
            }
    
            //SetCompany1是深拷贝
            public void SetCompany1(string address)
            {
                Company c = (Company)company.Clone();
                c.Address = address;
                company = c;
            }
    
            #endregion
    
            public void Show()
            {
                Console.WriteLine("id:{0} exp:{1} company:{2}", ID, Exp, company.Address);
            }
    
            public object Clone()
            {
                return MemberwiseClone();
            }
        }
    
    //公司类,也可以拷贝
    public class Company : ICloneable
        {
    
            private string address;
    
            public string Address
            {
                get { return address; }
                set { address = value; }
            }
    
            public object Clone()
            {
                return MemberwiseClone();
            }
        }
    
    //客户端
                Prototype p1 = new Prototype("1");
                p1.SetExp("半年经验");
                p1.SetCompany("世纪财富中心");
                //p1.Show();
                Prototype p2 = (Prototype)p1.Clone();
                p2.SetExp("1年经验");
                p2.SetCompany("帝国大厦");
                //p2.Show();
                Prototype p3 = (Prototype)p1.Clone();
                p3.SetCompany1("华尔街");
                //p3.Show();
    
                p1.Show();
                p2.Show();
                p3.Show();
    
                //执行客户端的注释代码会发现有不同的结果,所以代码的执行逻辑也必须要理清

         运行结果:

    结果1:

    结果2:

    结果3:

     

         代码的分析:

          在客户端代码中p2没有调用构造方法,而是调用p1的clone方法,所以内存中没有产生新的对象,p2引用p1的对象。当p2修改company时,p1的company也发生改变。p3同样调用p1的clone方法,但是p3使用SetCompany1来设置company,在SetCompany1的内部并不是直接给company赋值,而是重新克隆company,赋值给company字段,所以p3修改并没有将p1,p2的修改覆盖。出现运行结果1。

          在调整代码的执行顺序之后,可以看到p2的修改似乎没有影响p1(如结果2),但其实p2的修改已经影响了p1,只是p1的输出在前面执行。于是在结果3中可以看到修改。

          从以上代码及其结果,不难看出是深拷贝和浅拷贝以及代码的执行顺序的影响。

          原源码(大话设计模式P88)是通过在私有的构造函数中克隆WorkExperience,并将克隆体赋值给自己,从而产生区别。大话设计模式P87有深拷贝,浅拷贝的介绍。

          结合C++的知识,浅拷贝是将新对象的指针指向原有的对象,不再复制原有对象。深拷贝是将原有对象复制一个份,让新对象的指针指向复制后的地址。(如下附图)

          结合C#的知识,浅拷贝是新对象引用原有对象,内存中没有产生新的对象。深拷贝是在内存中开辟空间创建对象,并将原有对象的值复制,新对象引用内存中新产生的对象,只是与原有对象的值一致,从内存地址上看和原有对象没有关系。     

          应用的场景:

          从代码角度来说,避免创建对象时的初始化过程(如果这个过程占用的时间和资源都非常多),或者是希望避免使用工厂方法来实现多态的时候,可以考虑原型模式。

      从应用角度来说, 如果你创建的对象是多变化、多等级的产品,或者产品的创建过程非常耗时的时候(比如,有一定的计算量,或者对象创建时需要从网络或数据库中获取一定的数据),或者想把产品的创建独立出去,不想了解产品创建细节的时候可以考虑使用。

         注意事项:

         深拷贝和浅拷贝的使用场景,哪些是公有的允许修改的,哪些是不允许修改的。值类型和引用类型在深浅拷贝中的结果是不一样的。

         拷贝原型并进行修改意味着原型需要公开更多的数据,对已有系统实现原型模式可能修改的代价比较大。

    附图:

    部分内容摘自   http://www.cnblogs.com/promise-7/archive/2012/06/01/2530734.html

    菜鸟D希望这篇文章对您有所帮助。

  • 相关阅读:
    代码的未来
    shell脚本中的[]/[[]]区别
    shell脚本判断文件类型
    muduo库安装
    protobuf安装
    讲给普通人听的分布式数据存储(转载)
    Oracle OCCI学习之开篇
    浅谈MySQL索引背后的数据结构及算法(转载)
    5.7版本mysql查询报错:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:...this is incompatible with sql_mode=only_full_group_by
    IDEA启动tomcat报错:java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext、ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component
  • 原文地址:https://www.cnblogs.com/cnDqf/p/4108266.html
Copyright © 2020-2023  润新知