原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。
//工作经历类
class WorkExperience
{
public string WorkDate
{
get;
set;
}
public string Company
{
get;
set;
}
}
//简历类
class Resume : ICloneable
{
private string name;
private string sex;
private string age;
private WorkExperience work;
public Resume( string name )
{
this.name = name;
work = new WorkExperience( );
}
public void SetPersonalInfo( string sex, string age )
{
this.sex = sex;
this.age = age;
}
public void SetWorkExperience( string workDate, string company )
{
work.WorkDate = workDate;
work.Company = company;
}
public void Display( )
{
Console.WriteLine( "{0} {1} {2}", name, sex, age );
Console.WriteLine( "工作经历: {0} {1}", work.WorkDate, work.Company );
}
///
/// 浅拷贝:针对引用类型只复制引用不复制引用对象,即原始对象和副本引用同一个对象
///
///
public Object Clone( )
{
return (Object)this.MemberwiseClone( );
}
}
static void Main( string[ ] args )
{
Resume a = new Resume( "andy" );
a.SetPersonalInfo( "男", "18" );
a.SetWorkExperience( "1992-2000", "XX公司" );
Resume b = (Resume)a.Clone( );
b.SetWorkExperience( "1992-2002", "XY公司" );
Resume c = (Resume)a.Clone( );
b.SetWorkExperience( "1992-2001", "YY公司" );
a.Display( );
b.Display( );
c.Display( );
Console.Read( );
}
运行结果:
上述代码运行完成后,三次显示的结果都是最后一次设置的值。这是因为由于浅表复制,所以对于值类型,没什么问题,对引用类型,就只是复制了引用,对引用的对象还是指向了原来的对象,所以就会出现给a,b,c三个引用设置“工作经历”,却同时看到三个引用都是最后一次设置,因为三个引用都指向了同一个对象。
浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制:把引用对象的变量指向复制过来的新对象,而不是原有的被引用的对象。
简历的深复制实现:
//工作经历
class WorkExperience : ICloneable
{
public string WorkDate
{
get;
set;
}
public string Company
{
get;
set;
}
//“工作经历”类实现克隆方法
public Object Clone( )
{
return (Object)this.MemberwiseClone( );
}
}
//简历
class Resume : ICloneable
{
private string name;
private string sex;
private string age;
private WorkExperience work;
public Resume( string name )
{
this.name = name;
work = new WorkExperience( );
}
//提供Clone方法调用的私有构造函数,以便克隆“工作经历”的数据
private Resume( WorkExperience work )
{
this.work = (WorkExperience)work.Clone( );
}
public void SetPersonalInfo( string sex, string age )
{
this.sex = sex;
this.age = age;
}
public void SetWorkExperience( string workDate, string company )
{
work.WorkDate = workDate;
work.Company = company;
}
public void Display( )
{
Console.WriteLine( "{0} {1} {2}", name, sex, age );
Console.WriteLine( "工作经历: {0} {1}", work.WorkDate, work.Company );
}
///
/// 深拷贝:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
///
///
public Object Clone( )
{
//调用私有构造方法,让“工作经历”克隆完成,此处克隆会调用私有构造函数中的(WorkExperience)work.Clone( )实现“工作经历”深拷贝
Resume obj = new Resume( this.work );
//给这个“简历”对象的相关字段赋值,最终返回一个深复制的简历对象
obj.name = this.name;
obj.sex = this.sex;
obj.age = this.age;
return obj;
}
}
static void Main( string[ ] args )
{
Resume a = new Resume( "andy" );
a.SetPersonalInfo( "男", "18" );
a.SetWorkExperience( "1992-2000", "XX公司" );
Resume b = (Resume)a.Clone( );
b.SetWorkExperience( "1992-2002", "YY公司" );
Resume c = (Resume)a.Clone( );
c.SetWorkExperience( "1992-2001", "ZZ公司" );
a.Display( );
b.Display( );
c.Display( );
Console.Read( );
}
运行结果:
由于在一些特定场合,会经常涉及深复制或浅复制,比如说,数据集对象DataSet,它就有Clone()方法和Copy()方法。Clone()方法用来复制DataSet的结构,但不复制DataSet的数据,实现了原型模式的浅复制。Copy()方法不但复制结构,也复制数据,其实就是实现了原型模式的深复制。
原型模式的优点有:
原型模式的缺点有: