-
设计模式(6):原型模式(Prototype patterns)
-
-
原型模式(Prototype patterns)
-
-
动机
-
在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变.
-
-
意图
-
使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
-
.NET在System命名空间中提供了ICloneable接口,其中就有唯一的一个方法Clone(),这样就只需要实现这个接口就可以完成原型模式了
-
-
原型模式(Prototype patterns)结构图
-
-
简历的原型实现
-
-
-
class Resume
{
private string name;
private string sex;
private string age;
private string tiemArea;
private string company;
public Resume(string name)
{
this.name=name;
}
public void setPersonalnfo(string sex,string age)
{
this.sex=sex;
this.age=age;
}
public void SetWorkExperience(string tiemArea,string company)
{
this.tiemArea=tiemArea;
this.company=company;
}
public void Display()
{
Console.WriteLine("{0} {1} {2}",name,sex,age);
Console.WriteLine("工作经验 {0} {1}",timeArea,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=a;这其实是在传引用,而不是传值,这样做如同在b纸张上写着简历在a处一样,没有实际的内容的
Resume b=(Resume)a.clone();
b.SetWorkExperience("1998-2000","yy公司");
Resume c=(Resume)a.Clone();
c.SetPersonalInfo("男","24");
a.display();
b.display();
c.display();
} - 结果显示:
-
大鸟 男 29
工作经历 1998-2000 xx公司
大鸟 男 29
工作经历 1998-2000 yy公司
大鸟 男 24
工作经历 1998-2000 xx公司 - MemberwiseClone()方法是这样,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用的对象;因此,原始对象及其复本引用同一对象在现实设计当中,一般会再有一个"工作经历"类,当中有"时间区别"和"公司名称"等属性,"简历"类直接调用这个对象即可。
-
浅复制
-
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;}
}
}
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.MeberwiseClone();
}
} - 客户端代码:
-
static void Main(string[] args)
{
Resume a=new Resume("大鸟");
a.SetpersonalInfo("男","29");
a.workExperience("1998-2000","xx公司");
//b和c都克隆于a,但当它们都设置了"工作经历"时,我们希望的结果是三个的显示不一样
Resume b=(Resume)a.Clone();
b.workExperience("1998-2006","yy公司");
Resume c=(Resume)a.Clone();
c.workExperience("1998-2003","zz公司");
a.Display();
b.Display();
b.Display();
} - 显示结果:
-
//可惜,没有达到我们的要求,三次显示的结果都是最后一次设置的值
大鸟 男 29
工作经历 1998-2000 zz公司
大鸟 男 29
工作经历 1998-2000 zz公司
大鸟 男 29
工作经历 1998-2000 zz公司 -
简历的深复制:
-
class WorkExperience :ICloneable//让"工作经历"实现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;}
}
public object Clone()//"工作经历"类实现克隆方法
{
return (object)this.MemberwisseClone();
}
}
calss Resume:ICloneable
{
private string name;
private string sex;
private string age;
private WorkExperience work;
public Resume(string name)
{
this.name=name;
work=new WorkExperience();
}
private Resume(WorkExperience work)
{//提供Clone方法调用的私有构造函数,以便克隆"工作经历"的数据
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()
{
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("大鸟");
a.SetpersonalInfo("男","29");
a.workExperience("1998-2000","xx公司");
Resume b=(Resume)a.Clone();
b.workExperience("1998-2006","yy公司");
Resume c=(Resume)a.Clone();
c.workExperience("1998-2003","zz公司");
a.Display();
b.Display();
b.Display();
} - 显示结果:
-
//达到了我们希望的三次显示的结果不同的要求
大鸟 男 29
工作经历 1998-2000 xx公司
大鸟 男 29
工作经历 1998-2006 yy公司
大鸟 男 29
工作经历 1998-2003 zz公司