设计模式学习总结-原型模式(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进行浅复制时,原型模式是内存二进制流的拷贝,构造函数是不会执行的。

posted @ 2012-07-11 18:19  ejiyuan  阅读(1324)  评论(0编辑  收藏  举报