设计模式学习总结-原型模式(Prototype Method)
问题:
在程序设计中,我们可能由于某种特定的需要,复制一个对象的结构,与对象的值,动态的获取获取对象运行时的状态,最简单的解决办法是 new 一个对象新的对象,然后将对象的属性值一一赋值给新的对象,这样要一一列出对象的属性赋值,操作起来太复杂,而且及其容易出错,落下某个属性的赋值。能否让对象本身提供一个自我复制的功能,客户端只需简单的调用这个方法就能完成对象的复制。
定义:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
意图:
Prototype模式允许一个已存在的对象通过创建的接口(Clone),通过拷贝自己来实施创建另外一个可定制的对象(定制好属性值然后批量复制),根本无需知道任何如何创建的细节。Clone)。
Clone()实现和具体的实现语言相关。.NET中一般使用Object的MemberwiseClone()方法创建对象的浅表副本实现浅复制。
参与者:
•Prototype(抽象原型)角色:
抽象原型角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体原型类所需的接口(.NET提供了一个定义方法Clone()方法的ICloneable接口,作为系统中的通用Prototype)。
•ConcretePrototype(抽象原型)角色:
被复制的对象。此角色需要实现抽象的原型角色所要求的接口。实现具体的对象复制方法。
UML:
浅复制与深复制:
•浅复制:如果字段是值类型的(包括string),则对该字段执行逐位复制,如字段是引用类型,则复制引用但不自制引用的对象。因此,原始对象及其复本引用同一对象。通过Object的MemberwiseClone()方法即可实现。
•深复制:如果字段是值类型的,则对该字段执行逐位复制,如字段是引用类型,则复制引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。让子类也继承Prototype角色几口实现Clone()方法,使用逐层克隆赋值引用类型字段的办法完成。
实例说明:
诺基亚手机工厂
同款型号的手机生产多个不用每次都要通过生产工厂,可以根据已生产好的某款通过复制的办法来完成。
uml图如下:
代码:
浅复制:
/// 抽象原型角色
/// </summary>
public interface IPrototypePhone
{
object Clone();
}
/// <summary>
/// 具体原型角色
/// </summary>
public class ConcretePrototypePhone : IPrototypePhone
{
public string Name { get; set; }
public string Cpu { get; set; }
public string Mb { get; set; }
public float MemorySize { get; set; }
public string System { get; set; }
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();
}
深复制:
/// 具体原型角色,实现.net提供的通用 抽象原型角色System.ICloneable
/// </summary>
public class ConcretePrototypePhone : System.ICloneable
{
public string Name { get; set; }
public ConcretePrototypeCpu Cpu { get; set; }
public string Mb { get; set; }
public float MemorySize { get; set; }
public string System { get; set; }
public object Clone()
{
//看克隆父对象
ConcretePrototypePhone obj = (ConcretePrototypePhone)this.MemberwiseClone();
//克隆子对象,将子对象的引用指向克隆出的新对象
obj.Cpu = (ConcretePrototypeCpu)this.Cpu.Clone();
return obj;
}
}
public class ConcretePrototypeCpu : System.ICloneable
{
public string Name { get; set; }
public float Frequency { get; set; }
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进行浅复制时,原型模式是内存二进制流的拷贝,构造函数是不会执行的。