• 设计模式学习总结原型模式(Prototype Method)


    问题:
    在程序设计中,我们可能由于某种特定的需要,复制一个对象的结构,与对象的值,动态的获取获取对象运行时的状态,最简单的解决办法是 new 一个对象新的对象,然后将对象的属性值一一赋值给新的对象,这样要一一列出对象的属性赋值,操作起来太复杂,而且及其容易出错,落下某个属性的赋值。能否让对象本身提供一个自我复制的功能,客户端只需简单的调用这个方法就能完成对象的复制。

    定义:

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

    意图:
    Prototype模式允许一个已存在的对象通过创建的接口(Clone),通过拷贝自己来实施创建另外一个可定制的对象(定制好属性值然后批量复制),根本无需知道任何如何创建的细节。Clone)。
    Clone()实现和具体的实现语言相关。.NET中一般使用Object的MemberwiseClone()方法创建对象的浅表副本实现浅复制。
    参与者:
    •Prototype(抽象原型)角色:
    抽象原型角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体原型类所需的接口(.NET提供了一个定义方法Clone()方法的ICloneable接口,作为系统中的通用Prototype)。

    •ConcretePrototype(抽象原型)角色:
    被复制的对象。此角色需要实现抽象的原型角色所要求的接口。实现具体的对象复制方法。

    UML:

    浅复制与深复制:

    •浅复制:如果字段是值类型的(包括string),则对该字段执行逐位复制,如字段是引用类型,则复制引用但不自制引用的对象。因此,原始对象及其复本引用同一对象。通过Object的MemberwiseClone()方法即可实现。
    •深复制:如果字段是值类型的,则对该字段执行逐位复制,如字段是引用类型,则复制引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。让子类也继承Prototype角色几口实现Clone()方法,使用逐层克隆赋值引用类型字段的办法完成。

    实例说明:

    诺基亚手机工厂
    同款型号的手机生产多个不用每次都要通过生产工厂,可以根据已生产好的某款通过复制的办法来完成。

    uml图如下:

     

    代码:

    浅复制:

    /// <summary>
    /// 抽象原型角色
    /// </summary>
    public interface IPrototypePhone
    {
        object Clone();
    }
    /// <summary>
    /// 具体原型角色
    /// </summary>
    public class ConcretePrototypePhone : IPrototypePhone
    {
        public string Name { getset; }
        public string Cpu { getset; }
        public string Mb { getset; }
        public float MemorySize { getset; }
        public string System { getset; }

        public object Clone()
        {
            //使用内置MemberwiseClone()方法克隆对象
            return this.MemberwiseClone();
        }
    }
    public void PrototypeTest()
    {

        ConcretePrototypePhone obj = new ConcretePrototypePhone();
        obj.Cpu = "ARM_27";
        obj.Mb = "N8_1op";
        obj.MemorySize = 375;
        obj.Name = "N8";
        obj.System = "塞班";
        var n8 = obj.Clone();
    }

    深复制:

    /// <summary>
    /// 具体原型角色,实现.net提供的通用 抽象原型角色System.ICloneable
    /// </summary>
    public class ConcretePrototypePhone : System.ICloneable
    {
        public string Name { getset; }
        public ConcretePrototypeCpu Cpu { getset; }
        public string Mb { getset; }
        public float MemorySize { getset; }
        public string System { getset; }

        public object Clone()
        {
            //看克隆父对象
            ConcretePrototypePhone obj = (ConcretePrototypePhone)this.MemberwiseClone();
            //克隆子对象,将子对象的引用指向克隆出的新对象
            obj.Cpu = (ConcretePrototypeCpu)this.Cpu.Clone();
            return obj;
        }
    }
    public class ConcretePrototypeCpu : System.ICloneable
    {
        public string Name { getset; }
        public float Frequency { getset; }
        public object Clone()
        {
            return this.MemberwiseClone();
        }
    }
    public void PrototypeTest()
    {

        ConcretePrototypePhone obj = new ConcretePrototypePhone();
        obj.Cpu = new ConcretePrototypeCpu() { Frequency = 2.4F, Name = "Ar700" };
        obj.Mb = "N8_1op";
        obj.MemorySize = 375;
        obj.Name = "N8";
        obj.System = "塞班";
        ConcretePrototypePhone n8 = (ConcretePrototypePhone)obj.Clone();
        n8.Cpu = new ConcretePrototypeCpu() { Frequency = 2.0F, Name = "Ar70" };
    }

     优点:
    •可在不用重新初始化对象,而是动态地获取对象运行时的状态。
    •屏蔽对象的复制细节,客户端无需关心复制细节,对象的复制被封闭在对象内部,怎么样复制有对象本身决定。
    •在某些环境下,复制对象比创建新对象更有效,因为对象的构造函数是不会执行的。
    缺点:
    •实现深层复制时实现比较复杂。

    应用情景:
    •复制对象的结构与数据。
    •希望对目标对象的修改不影响既有的原型对象。
    •创建对象成本较大的情况下(初始化需占用较长时间,占用太多CPU资源或网络资)
    PS:
    •在调用MemberwiseClone进行浅复制时,原型模式是内存二进制流的拷贝,构造函数是不会执行的。

  • 相关阅读:
    python eval()函数
    Linux利用Sysctl命令调整内核参数
    Cookie测试的测试点
    python脚本对 MySQL 数据库进行增删改查
    页面加载经历的过程【转载】
    【转载】shell基础知识
    windows下查看端口占用情况
    Python的hashlib提供了常见的摘要算法
    Python统计文件夹下各个子目录中的文件个数
    Python读取文件下的图片格式
  • 原文地址:https://www.cnblogs.com/ejiyuan/p/2586781.html
Copyright © 2020-2023  润新知