原型模式(Prototype Pattern):
用原型实例创建指定的对象的种类,并且通过拷贝这些原型创建新的对象。
Prototype:原型类,声明一个克隆自身的接口。
ConcretePrototype:具体的原型类,继承Prototype,实现一个克隆自身的操作。
Clinet:让一个原型克隆自身从而创建一个新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
原型模式代码:
原型类(Prototype):
abstract class Prototype
{
private string id;
public Prototype(string id)
{
this.id = id;
}
public string Id
{
get { return id; }
}
//抽象类关键是具有这样一个Clone方法
public abstract Prototype Clone();
}
具体原型类(ConcretePrototype):
class ConcretePrototype : Prototype
{
public ConcretePrototype(string id)
: base(id)
{
}
//创建当前对象的浅表副本。方法是创建一个新对象,然后讲当前对象的非
//静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制
//如果字段是引用类型,则复制引用但不复制引用的对象,因此,原始对象及
//副本引用同一对象
public override Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
客户端代码:
ConcretePrototype p1=new ConcretePrototype("I");
//克隆类ConcretePrototype的对象p1就能得到新的实例c1
ConcretePrototype c1=(ConcretePrototype)p1.Clone();
Console.WtiteLine("Cloned:{0}",c1.id);
说明:.Net在System命名空间中提供了ICloneable接口,其中就是唯一的一个方法Clone(),所以
只要实现这个接口就可以完成原型模式了
运用:一般在初始化的信息不发生变化的情况下,克隆是最好的办法。这样既隐藏了对象的创建细节,
又对性能有大大的提高。
浅表复制(Shallow Copy)和深层复制(Deep Copy):MemberwiseClone()方法是如果字段是值类型的,则对该字段执行逐位复制;如果字段是
引用类型,则复制引用但不复制引用的对象;进许浅表复制时,如果父类包含的子引用对象发生变化,这个变化同时也出现在它的浅表
复制的克隆对象中;深层复制中,如果父类对象发生改变,这个变化不会出现在它的深层复制的克隆对象中。
实例
1:简历的原型模式实现
public class Resume : ICloneable
{
private string _name;
private string _sex;
private int _age;
private string _timeArea;
private string _company;
public Resume(string name)
{
this._name = name;
}
//设置个人信息
public void SetPersonalInfo(string sex, int age)
{
this._sex = sex;
this._age = age;
}
//设置工作经历
public void SetWorkExperience(string timeArea, string company)
{
this._timeArea = timeArea;
this._company = company;
}
//显示简历
public void Display()
{
Console.WriteLine("{0} {1} {2}", _name, _sex, _age.ToString());
Console.WriteLine("工作经历:{0} {1}", _timeArea, _company);
}
#region ICloneable 成员
//自身克隆方法
public object Clone()
{
//浅表复制
return (Object)this.MemberwiseClone();
}
#endregion
}
//原型模式(值类型克隆)
Resume a = new Resume("埃里克斯");
a.SetPersonalInfo("男", 25);
a.SetWorkExperience("2009-2010", "XX公司");
//只需要调用Clone方法就可以实现新简历的生成,并且可以再修改新简历的细节
Resume b = (Resume)a.Clone();
b.SetWorkExperience("2010-2011", "YY公司");
Resume c = (Resume)a.Clone();
c.SetPersonalInfo("女", 24);
a.Display();
b.Display();
c.Display();
输出结果:
埃里克斯 男 25
2009-2010 XX公司
埃里克斯 男 25
2010-2011 YY公司
埃里克斯 女 24
2009-2010 XX公司
如果此时工作经历是一个单独的类,如下
/// <summary>
/// 工作经历类
/// </summary>
public class WorkExperience
{
private string _workDate;
public string WorkDate
{
get { return _workDate; }
set { _workDate = value; }
}
private string _company;
public string Company
{
get { return _company; }
set { _company = value; }
}
}
/// <summary>
/// 简历类,深层复制
/// </summary>
public class Resume2:ICloneable
{
private string _name;
private string _sex;
private int _age;
//引用“工作经历”对象
private WorkExperience work;
public Resume2(string name)
{
this._name = name;
work = new WorkExperience();
}
//设置个人信息
public void SetPersonalInfo(string sex, int age)
{
this._sex = sex;
this._age = age;
}
//设置工作经历
public void SetWorkExperience(string timeArea, string company)
{
work.WorkDate = timeArea;
work.Company= company;
}
//显示简历
public void Display()
{
Console.WriteLine("{0} {1} {2}", _name, _sex, _age.ToString());
Console.WriteLine("工作经历:{0} {1}", work.WorkDate, work.Company);
}
#region ICloneable 成员
public object Clone()
{
return (Object)this.MemberwiseClone();
}
#endregion
}
//原型模式(引用类型克隆)
Resume2 a2 = new Resume2("迈克");
a2.SetPersonalInfo("男", 26);
a2.SetWorkExperience("2009-2010", "XX公司");
Resume2 b2 = (Resume2)a2.Clone();
b2.SetWorkExperience("2010-2011", "YY公司");
Resume2 c2 = (Resume2)a2.Clone();
c2.SetPersonalInfo("男", 22);
c2.SetWorkExperience("2011-2012", "ZZ公司");
//显示结果都是最后一次设置的值
a2.Display();
b2.Display();
c2.Display();
显示结果:
迈克 男 26
2011-2012 ZZ公司
迈克 男 26
2011-2012 ZZ公司
迈克 男 22
2011-2012 ZZ公司
工作经历显示的都是最后设置的值
让工作经历类也继承ICloneable接口,实现自身的克隆
/// <summary>
/// 工作经历类:继承ICloneable接口
/// </summary>
public class WorkExperience2:ICloneable
{
private string _workDate;
public string WorkDate
{
get { return _workDate; }
set { _workDate = value; }
}
private string _company;
public string Company
{
get { return _company; }
set { _company = value; }
}
#region ICloneable 成员
//克隆自身方法
public object Clone()
{
return (Object)this.MemberwiseClone();
}
#endregion
}
/// <summary>
/// 深层复制
/// </summary>
public class Resume3:ICloneable
{
private string _name;
private string _sex;
private int _age;
//引用“工作经历”对象
private WorkExperience2 _work;
public Resume3(string name)
{
this._name = name;
_work = new WorkExperience2();
}
//提供Clone方法调用的私有构造函数,以便克隆“工作经历”的数据
public Resume3(WorkExperience2 work)
{
this._work = (WorkExperience2)work.Clone();
}
//设置个人信息
public void SetPersonalInfo(string sex, int age)
{
this._sex = sex;
this._age = age;
}
//设置工作经历
public void SetWorkExperience(string timeArea, string company)
{
_work.WorkDate = timeArea;
_work.Company = company;
}
//显示简历
public void Display()
{
Console.WriteLine("{0} {1} {2}", _name, _sex, _age.ToString());
Console.WriteLine("工作经历:{0} {1}", _work.WorkDate, _work.Company);
}
#region ICloneable 成员
public object Clone()
{
//调用私有的构造函数,让“工作经历”克隆完成,然后再给这个“简历”
//对象的相关字段赋值,最终返回一个深复制的简历对象
Resume3 obj = new Resume3(this._work);
obj._name = this._name;
obj._sex = this._sex;
obj._age = this._age;
return obj;
}
#endregion
//原型模式(引用类型深层复制克隆)
Resume3 a3 = new Resume3("迈克");
a3.SetPersonalInfo("男", 26);
a3.SetWorkExperience("2009-2010", "XX公司");
Resume3 b3 = (Resume3)a3.Clone();
b3.SetWorkExperience("2010-2011", "YY公司");
Resume3 c3 = (Resume3)a3.Clone();
c3.SetPersonalInfo("男", 22);
c3.SetWorkExperience("2011-2012", "ZZ公司");
a3.Display();
b3.Display();
c3.Display();
显示结果:
迈克 男 26
2009-2010 XX公司
迈克 男 26
2010-2011 YY公司
迈克 男 22
2011-2012 ZZ公司