原型设计模式






4.75/5 (13投票s)
本文通过一个案例研究,展示了我们如何将原型模式用于 Elizabeth 的趣味活动。
背景
在我上一篇文章中,我通过一个伊丽莎白有趣活动的例子介绍了建造者模式。
当伊丽莎白想制作动物时,她需要为每只动物制作头部、身体、腿、手臂和尾巴。她先用模具工具集制作好动物的所有身体部分,然后将它们组装起来制作成一只动物。
在她的有趣活动中,伊丽莎白使用了建造者模式来制作动物。例如,当她想制作一只猴子时,一旦所有五个部分都完成,她就会将它们粘合在一起,然后进行装饰。
第二天,如果她想再次制作相同的动物,她需要一遍又一遍地重复相同的步骤。最后她厌倦了这样做,所以她问我是否有一个复印机可以帮助她随时复制她想要的动物。嗯,看来伊丽莎白也想遵循“不要重复自己”的编程规则。
所以,看起来原型设计模式可以满足伊丽莎白的愿望。在这种情况下,伊丽莎白可以复制她的第一只动物(原型动物)并以不同的方式进行装饰。她还可以使用她复制的动物作为原型来制作其他动物。
引言
原型设计模式也是我们用于获取特定类对象实例的一种模式,例如建造者和工厂模式。我们不必每次都创建一个全新的对象,而是可以立即复制一个已有的对象(可以用作原型的对象)并开始使用它。这样,我们就无需重复创建我们想要使用的对象的构建过程。新的复制对象与原始原型对象完全独立,可以用于任何不会影响原版的目的。复制现有对象没有限制,任何现有对象都可以被复制。本文介绍了我们如何使用原型设计模式来为伊丽莎白的动物实现。
原型设计模式结构

类图

实现代码
原型对象
动物
Animal
类是我们想要使其可克隆的类。在 C# .NET 中,我们继承 ICloneable
接口来使我们的类成为可克隆类。为了实现 clone()
方法,可以使用浅拷贝或深拷贝。根据我们的需求,我们也可以选择不同的策略来实现浅拷贝或深拷贝。但是,如果我们进行浅拷贝,类中的所有引用变量仍将指向原始原型对象所在的相同地址。Animal
类包含一个接受另一个 Animal
作为参数的构造函数,我在这里编写了所有的克隆过程,这样它就可以在自己的 clone()
方法中被调用,以实现自我克隆的能力。另一种使 Animal
可克隆的方法是使用 Serialize
属性使 Animal
类可序列化。我们可以将当前对象序列化到 MemoryStream
,然后将其反序列化为一个新对象作为复制的对象。请通过 MSDN 网站了解更多关于如何进行浅拷贝和深拷贝的详细信息。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace PrototypeDesignPattern
{
public class Animal : ICloneable
{
public Head AHead { get; set; }
public List<leg> Legs { get; set; }
public Tail ATail { get; set; }
public string Name { get; set; }
public Animal()
{
AHead = new Head();
Legs = new List<leg>();
ATail = new Tail();
}
//Constructor to implement the deep copy here
public Animal(Animal aAnimal)
{
Name = aAnimal.Name;
AHead = (Head)aAnimal.AHead.Clone();
Legs = new List<leg>();
foreach (Leg aLeg in aAnimal.Legs)
{
Legs.Add((Leg)aLeg.Clone());
}
ATail = (Tail)aAnimal.ATail.Clone();
}
//Helper method to show the result from client
public void Dispaly()
{
Console.WriteLine("I am a " + Name);
AHead.Display();
foreach (Leg aleg in Legs)
{
aleg.Display();
}
ATail.Display();
Console.WriteLine();
}
#region ICloneable Members
//call deep coy to perform clone process
public object Clone()
{
return new Animal(this);
}
#endregion
}
}
}
Head
Head
类是我们将在 Animal
类中声明的另一个类。由于它是我们 Animal
类中的一个引用对象,我也实现了 Clone()
方法,以便在我们需要克隆它时使其自身可克隆。与 Animal
类的区别在于,我在 Clone()
方法中使用了 MemberwiseClone()
来复制它。 .NET 的 MemberwiseClone()
帮助我们对对象进行浅拷贝。由于我的 head 类中只有 Number
(int
类型)和 Name
(string
是引用,但它也是一个不可变的类型,不能被更改。所以,无论是对它进行浅拷贝还是深拷贝都没有区别),MemberwiseClone()
应该能很好地处理它。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace PrototypeDesignPattern
{
public class Head : ICloneable
{
public int Number { get; set; }
public string Name { get; set; }
public void Display()
{
Console.WriteLine("I have {0} {1} ", Number, Name);
}
#region ICloneable Members
//create a shallow copy of current object
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}
}
}
腿
与 Head
相同,Leg
类也继承 ICloneable
以使其自身可被复制。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace PrototypeDesignPattern
{
public class Leg : ICloneable
{
public string Side { get; set; }
public string Name { get; set; }
public void Display()
{
Console.WriteLine("This is my {0} {1} ", Side, Name);
}
#region ICloneable Members
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}
}
}
尾巴
Tail
类是另一个可克隆类,与 Head
相同。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace PrototypeDesignPattern
{
public class Tail : ICloneable
{
public string Color { get; set; }
public void Display()
{
Console.WriteLine("My tail is {0}", Color);
}
#region ICloneable Members
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}
}
}
客户端应用程序
从客户端来看,伊丽莎白将创建第一个动物对象。之后,她将简单地复制她的第一个动物来玩。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using www.askbargains.com.PrototypeDesignPattern;
namespace www.askbargains.com
{
namespace Client
{
class Program
{
static void Main(string[] args)
{
//Elizabeth starts building her first animal
Animal firstAnimal = new Animal();
firstAnimal.Name = "Deer";
//work on head
firstAnimal.AHead.Name = "Antlers";
firstAnimal.AHead.Number = 2;
Leg leftLeg = new Leg();
leftLeg.Side = "Left";
leftLeg.Name = "Hoove";
Leg rightLeg = new Leg();
rightLeg.Side = "Right";
rightLeg.Name = "Hoove";
firstAnimal.Legs.Add(leftLeg);
firstAnimal.Legs.Add(rightLeg);
firstAnimal.ATail.Color = "Brown";
//Elizabeth copied the firstAnimal(prototype)
Animal copiedAnimal =(Animal)firstAnimal.Clone();
Console.WriteLine("Display the first animal");
firstAnimal.Dispaly();
Console.WriteLine("Display the copied animal");
copiedAnimal.Dispaly();
//Elizabeth play aroud with the copiedAnimal
copiedAnimal.Name = "Copied Deer";
copiedAnimal.AHead.Name = "Antlers";
copiedAnimal.AHead.Number = 1;
//display the result
Console.WriteLine("Display the copied animal after some play.
Elizabeh only made 1 antler for it");
copiedAnimal.Dispaly();
Console.WriteLine("Display the original prototype");
firstAnimal.Dispaly();
//Elizabeth make an other copy by using the copiedAnimal as the prototype
Animal secondCopy = (Animal)copiedAnimal.Clone();
secondCopy.Name = "An other copy";
//Display the second copy
Console.WriteLine("Display the secnod copy animal");
secondCopy.Dispaly();
Console.Read();
}
}
}
}
一旦我们启动客户端应用程序,您将看到复制的对象与原型对象(firstAnimal
)完全相同。玩复制的对象不会影响原始原型。很酷。

结论
在本文中,我演示了如何使用原型模式来帮助我们复制现有对象。我还为建造者设计模式编写了另一篇文章,介绍了如何创建对象实例。
历史
- 2009 年 9 月 23 日:首次发布