给一个原型为类型,拷贝并创建一个新对象
原型模式有点像复印机,也有点像卡卡西的拷贝忍术,当然了这个模式下,你期望是完全复制还是,只是浅层复制,这取决于你的需求.在以原型为类型创建一个新的对象时,不需要关心它是怎么创建的.
浅复制被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象.
深复制把引用的变量指向复制过的新对象,而不是原有的被引用的对象.
UML图
当需要大量复制对象,其初始化状态又是一样的状况,当远程传输请求的数据库实体类,再次需要获取时,不必从数据库获得,直接通过原型模式 拷贝一份,附上新值再发送出去.如果一个对象的初始化需要许多其他对象的引用和其他资源繁琐的计算,可以使用.
优点
避免了重复大量的构造函数调用节省性能
规避了实例化多个相同对象的重复代码,提升效率
隐藏了制造新实例的复杂性,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。
缺点
如果创建的对象是轻类型对象,也就是构造起来不是很麻烦,那么使用new比clone()快不止一个数量级。但是如果是创建重的对象,构造对象超级麻烦,那么使用原型比new对象要快。不太适用于比较简单的对象构造。
举了打印简历的例子,一份简历和多份简历没有什么差别,内容也没有改动,简历有姓名,年龄,工作经历等信息,如果使用new的方式就需要多次的构造函数构造,并 给那些信息初始化赋值。使用原型模式,将自身拷贝一份返回,外界调用拷贝原型,所有的初始化信息也是原型相同的。这里涉及到深拷贝和浅拷贝,如果是引用类型要实现深拷贝,需要一层层逐一赋值。
using System;
namespace PrototypeMode
{
class Program
{
static void Main(string[] args)
{
Naruto naruto = new Naruto("鸣人", 16, 400);
naruto.Teammate = new SaSuke("佐助", 16, 300);
Console.WriteLine("--------------------naruto------------------------");
naruto.UseSkill(40);//400-40=360
naruto.UseSkill(250);//110
naruto.ShowTeammate();
Naruto naruto1 = (Naruto)naruto.Clone();
naruto1.Teammate.Name = "小樱";
Console.WriteLine("--------------------naruto1------------------------");
naruto1.UseSkill(100);//浅复制,但值类型是拷贝一个新的110-100=10
naruto1.UseSkill(100);//不够了
naruto1.ShowTeammate();
Console.WriteLine("--------------------naruto------------------------");
naruto.UseSkill(100);//浅复制,但值类型是不受影响的所有110-100=10
naruto.ShowTeammate();//浅复制,引用类型受影响,变成了复对象给定的内容, 小樱
Console.ReadKey();
}
}
public abstract class ClassSevenMember : ICloneable
{
protected string _name;
protected int age;
protected int chakra;
public string Name { get { return _name; } set { _name = value; } }
public ClassSevenMember(string @name, int age, int chakra)
{
this._name = @name;
this.age = age;
this.chakra = chakra;
}
public ClassSevenMember(ClassSevenMember classSevenMember)
{
}
public object Clone()
{
return this.MemberwiseClone();//浅复制
}
}
public class SaSuke : ClassSevenMember
{
public SaSuke(string name, int age, int chakra) : base(name, age, chakra)
{
}
}
public class Sakura : ClassSevenMember
{
public Sakura(string name, int age, int chakra) : base(name, age, chakra)
{
}
}
public class Naruto : ClassSevenMember
{
private ClassSevenMember teammate;
public ClassSevenMember Teammate { get { return teammate; } set { teammate = value; } }
public Naruto(string name, int age, int chakra) : base(name, age, chakra)
{
}
public void UseSkill(int chakra)
{
int sigleChakra = 100;
Console.WriteLine("===========想要凝聚{0}的查克拉============", chakra);
if (chakra > this.chakra)
{
Console.WriteLine("不行超标了,我只有{0}点的查克拉", this.chakra);
return;
}
if (chakra < sigleChakra) Console.WriteLine("{0}聚集查克拉量过少发动技能失败", _name);
else
Console.WriteLine("{1}发动了{0}次风遁螺旋丸手里剑", chakra / sigleChakra, _name);
this.chakra -= chakra;
}
public void ShowTeammate()
{
Console.WriteLine("我的队友是{0}", teammate.Name);
}
}
}
运行结果
只需在原代码中修改一部分
//添加一个构造函数
private Naruto(ClassSevenMember classSevenMember) : base(classSevenMember)//提供一个构造函数克隆队友的数据
{
teammate = (ClassSevenMember)classSevenMember.Clone();//其实这里也是浅表复制,但是里面的都是值类型和string,所以会全完拷贝一份新的
}
//添加一个克隆方法,进行深复制
new public object Clone()
{
Naruto naruto = new Naruto(this.teammate);
naruto._name = this._name;
naruto.age = this.age;
naruto.chakra = this.chakra;
return naruto;
// return this.MemberwiseClone();//浅复制
}
其他不变,客户端不变.
运行结果
PS:原型模式要注意运用场合,使用与那些对象实例需要大量初始化构造的例子,如果构造比较简单,初始化条件也很简单,使用new 比 clone还要效率高些.
深刻理解深浅复制的差别,对引用类型和值类型的影响.