什么是原型模式
原型模式:通过克隆原型类实例化的对象,从而创建新的对象
如何使用
让类实现 ICloneable 接口。
class Resume : ICloneable
{
string name;
string sex;
string age;
public Resume(string name)
{
this.name = name;
}
//设置个人信息
public void SetPersonalInfo(string sex,string age)
{
this.sex = sex;
this.age = age;
}
//实现接口的Clone方法
public object Clone()
{
return (Object)this.MemberwiseClone();
}
public void Display()
{
Console.WriteLine("{0} {1} {2}",name,sex,age);
}
}
其中,MemberwiseClone()方法是基类 Object 的一个方法,用来创建当前对象的浅表副本,即实现对象的浅复制。
该方法会创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型,则会把数据复制到新对象中;如果字段是引用类型,则只复制引用但不复制引用的对象,当前对象和新对象仍然指向堆上的同一个对象。
★为什么是复制非静态字段呢?
首先要明白静态字段和非静态字段的区别是什么。
静态字段:类中所有对象共享的字段,通过【类名.字段名】 访问
非静态字段:为每个对象所私有,即每个对象的字段值互不影响,通过【对象名.字段名】访问
所以复制的是非静态字段,而静态字段大家都能用,没必要复制。
用在哪?
个人理解:当我们需要创建同一个类的很多个对象时,就可以通过这种克隆的方式,来创建对象。而且还可以对每个对象单独修改,而不影响其他的对象。
优缺点
优点:①提高性能。通过原型模式创建对象的时候,不需要用构造函数一个个实例化创建,如果构造函数的执行时间很长的话,通过克隆可以大大提高性能。
缺点:①如果引用很多层,想要实现深复制的话,需要把每一层的引用类型都复制一遍,实现比较麻烦。②如果想要更改 Clone() 方法,则需要修改类,违背了“开闭原则”。
浅复制 vs 深复制
//浅复制代码
class Resume : ICloneable
{
string name;
private WorkExperience work;
public Resume(string name)
{
this.name = name;
work = new WorkExperience();
}
//设置工作经历
public void SetWorkExperience(string workDate,string company)
{
work.WorkDate = workDate;
work.Company = company;
}
public object Clone()
{
return (Resume)this.MemberwiseClone();
}
public void Display()
{
Console.WriteLine("{0}",name);
Console.WriteLine("工作经历: {0} {1}",work.WorkDate,work.Company);
}
}
class WorkExperience : ICloneable
{
string _workDate;
string _company;
public string WorkDate
{
set { _workDate = value; }
get { return _workDate; }
}
public string Company
{
set { _company = value; }
get { return _company; }
}
}
//客户端的代码
static void Main(string[] args)
{
Resume a = new Resume("大鸟");
a.SetWorkExperience("1998-2000", "xx公司");
Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006", "YY公司");
Resume c = (Resume)a.Clone();
c.SetWorkExperience("1998-2003", "ZZ公司");
a.Display();
b.Display();
c.Display();
Console.ReadKey();
}
//output(三个相同):
//大鸟 工作经历:1998-2003 ZZ公司
浅复制:当字段是引用类型的时候,只复制引用而不复制引用的对象。
//深复制代码
class Resume : ICloneable
{
string name;
private WorkExperience work;
public Resume(string name)
{
this.name = name;
work = new WorkExperience();
}
private Resume(WorkExperience work)
{
this.work = (WorkExperience)work.Clone();
}
//设置工作经历
public void SetWorkExperience(string workDate,string company)
{
work.WorkDate = workDate;
work.Company = company;
}
//深复制的clone方法实现与浅复制不同
public object Clone()
{
//重新实例化一个Resume对象,调用Resume的私有构造方法,将原型的work对象赋值给【复制的Resume的work对象】
Resume obj = new Resume(this.work);
//将原型其他的字段的值也赋值给复制的 Resume 对象
obj.name = this.name;
obj.sex = this.sex;
obj.age = this.age;
return obj;
}
public void Display()
{
Console.WriteLine("{0}",name);
Console.WriteLine("工作经历: {0} {1}",work.WorkDate,work.Company);
}
}
class WorkExperience : ICloneable
{
string _workDate;
string _company;
public string WorkDate
{
set { _workDate = value; }
get { return _workDate; }
}
public string Company
{
set { _company = value; }
get { return _company; }
}
//增添了Clone()方法,用来创建WorkExperience的浅表对象
public object Clone()
{
return (Object)this.MemberwiseClone();
}
}
//客户端代码同浅复制,这样各对象显示出来的就不一样了
深复制:当字段是引用类型的时候,不仅复制引用,也复制引用的对象
★string也是引用类型,按正常来说浅复制之后,它们都共用一个引用对象,但是为什么改变字段的内容之后,它们互不影响呢?
推荐大家看一下这篇博客:String到底是值类型还是引用类型(c#),相信大家看完之后就明白了。