魔术师手拿一张百元大钞,瞬间又变出两张。也像配钥匙一样,拿一把钥匙,老师傅就能做出另一个一模一样的。像这种复制我们并不陌生,类似于我们设计中的原型模式。
本文将从以下几点浅谈原型模式:
概述
结构图
浅复制深复制
总结
概述:
复制过程,并不是做一个抽象类,去实例化它。而是只需通过实现一个含有Clone()方法的接口就可以去克隆,这就是.NET在System命名空间中提供的ICloneable接口。用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。
结构图:
但,仅仅了解到这里是不够的。复制还有浅复制和深复制。掌握了它才能更好的运用复制模式。
浅复制:
浅复制:被复制对象的所有变量都含有与原来的对象相同的值。而所有的其他对象的引用都仍指向原来的对象。
结构图
代码
// 此为 工作经历 类
classWorkExperience
{
private string workDate;
public string WorkDate
{
get {return workDate ;}
set {workDate =value;}
}
private string company;
public string Company
{
get {return company ;}
set {company =value ;}
}
}
//简历类 其中会引用“工作经历”对象
class Resume:ICloneable //实现接口ICloneable ,该接口的方法就是Clone
{
private string name;
private string age;
private string sex;
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 voidSetWorkExperience(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("大鸟");
a.SetPersonalInfo("男","29");
a.SetWorkExperience("1998-2000","xx公司");
Resume b=(Resume)a.Clone();
b.SetWorkExperience("1992-2006","YY公司");
Resume c=(Resume)a.Clone();
c.SetWorkExperience("1998-2003","zz企业");
c.SetPersonalInfo("男", "24");
a.Display();
b.Display();
c.Display();
Console .Read ();
}
浅复制图示
如图,简历复制之后,它的“引用工作经历”处,仍需要引用。也就是说,浅复制并没有复制所引用的对象。也就是说,不管简历被复制多少分,工作经历类只有一个,因此也就可以解释,为什么代码中给abc三处工作经历设置,但却同时看到三个引用都是最好一次设置。因为三个引用,本来就是对一个对象的操作。
那我们看深复制是怎样的呢?
深复制
深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
代码结构图
代码
class WorkExperience:ICloneable
{
private string workDate;
publicstring WorkDate
{
get {return workDate ;}
set{workDate =value;}
}
private string company;
publicstring Company
{
get {return company ;}
set {company =value ;}
}
publicObject Clone()
{
return(Object)this.MemberwiseClone();
}
}
//简历
class Resume:ICloneable
{
privatestring name;
private string age;
private string sex;
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 voidSetWorkExperience(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()
{
Resume obj = new Resume(this.work);
obj.name = this.name;
obj.sex = this.sex;
obj.age = this.age;
return obj;
}
}
深复制图示
第一步,深复制让工作经历也实现克隆接口。复制工作经历。
第二步,把复制后的工作经历放到简历中。
第三步,此时将简历复制,并给这个简历对象的相关字段赋值,最终即返回一个深复制的简历对象。
我们从中可以看出,此时再第三步中,我们重新设置工作经历,也只会影响当前的一个。而不会影响到工作经历的原型。因此,当我们需要一变二二变三时,就要用到深复制。