什么是原型模式?
《西游记》中,孙悟空可以根据自己的形状复制(克隆)出多个身外身,如上图所示,这种技巧在面向对象软件设计领域被称之为原型模式,孙悟空被称之为原型对象。原型模式通过复制一个原型对象得到多个与原型对象一模一样的新对象。
原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
原型模式结构如下图所示
原型模式代码实现
通用实现方法
通用的克隆实现方法是在具体原型类的克隆方法中实例化一个与自身类型相同的对象并将其返回,并将相关的参数传入新创建的对象中,保证它们的成员变量相同。示意代码如下:
/// <summary>
/// 原型抽象类
/// </summary>
public abstract class Prototype
{
/// <summary>
/// 克隆方法
/// </summary>
/// <returns></returns>
public abstract Prototype Clone();
}
/// <summary>
/// 创建具体原型
/// </summary>
public class ConcretePrototype : Prototype
{
// 成员变量
public string Attr { get; set; }
/// <summary>
/// 克隆方法
/// </summary>
/// <returns></returns>
public override Prototype Clone()
{
ConcretePrototype prototype = new ConcretePrototype();
prototype.Attr = attr;
return prototype;
}
}
在客户类中只需要创建一个ConcretePrototype对象作为原型对象,然后调用其Clone()方法即可得到对应的克隆对象,如下代码片段所示:
ConcretePrototype prototype = new ConcretePrototype();
ConcretePrototype copy = (ConcretePrototype)prototype.Clone();
此方法是原型模式的通用实现,它与编程语言本身的特性无关,除C#外,其他面向对象编程语言也可以使用这种形式来实现对原型的克隆。
在原型模式的通用实现方法中,可通过手工编写Clone()方法来实现浅克隆和深克隆。对于引用类型的对象,可以在Clone()方法中通过赋值的方式来实现复制,这是一种浅克隆实现方案;如果在Clone()方法中通过创建一个全新的成员对象来实现复制,则是一种深克隆实现方案。C#语言中的字符串(string/String)对象存在特殊性,只要两个字符串的内容相同,无论是直接赋值还是创建新对象,它们在内存中始终只有一份。
C#中的MemberwiseClone()方法和ICloneable接口
在C#语言中,提供了一个MemberwiseClone()方法用于实现浅克隆,该方法使用起来很方便,直接调用一个已有对象的MemberwiseClone()方法即可实现克隆。如下代码所示:
/// <summary>
/// 原型抽象类
/// </summary>
public abstract class Prototype
{
/// <summary>
/// 克隆方法
/// </summary>
/// <returns></returns>
public abstract Prototype Clone();
}
/// <summary>
/// 创建具体原型
/// </summary>
public class ConcretePrototype : Prototype
{
// 成员变量
public string Attr { get; set; }
/// <summary>
/// 克隆方法
/// </summary>
/// <returns></returns>
public override Prototype Clone()
{
// 调用MemberwiseClone方法实现的是浅拷贝,另外还有深拷贝
return (Prototype)this.MemberwiseClone();
}
}
在客户类中可以直接调用原型对象的Clone()方法来创建新的对象,如下代码片段所示:
ConcretePrototype concretePrototypeA = new ConcretePrototype();
concretePrototypeA.Attr = "Monkey";
var ConcretePrototypeB = (ConcretePrototype)concretePrototypeA.Clone();
Console.WriteLine(concretePrototypeA == ConcretePrototypeB);
Console.WriteLine(concretePrototypeA.Attr == ConcretePrototypeB.Attr);
在上述客户类代码片段中,输出语句“Console.WriteLine(concretePrototypeA == ConcretePrototypeB);”的输出结果为“False”,输出语句“Console.WriteLine(concretePrototypeA.Member == ConcretePrototypeB.Member);”的输出结果为“True”,表明此处的克隆方法为浅克隆。
除了MemberwiseClone()方法,在C#语言中还提供了一个ICloneable接口,它也可以用来创建当前对象的拷贝,其代码如下:
//
// 摘要:
// Supports cloning, which creates a new instance of a class with the same value
// as an existing instance.
[ComVisible(true)]
public interface ICloneable
{
//
// 摘要:
// Creates a new object that is a copy of the current instance.
//
// 返回结果:
// A new object that is a copy of this instance.
object Clone();
}
ICloneable接口充当了抽象原型类的角色,具体原型类通常作为实现该接口的子类,如下代码所示:
public class ConcretePrototypeDeepClone : ICloneable
{
public CheryCar SmallCar { get; set; }
public object Clone()
{
ConcretePrototypeDeepClone copy = (ConcreteProtot