原型模式(ProtoType):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。字面理解其意思就是从一个对象创建另外一个可定制的对象,而无需知道任何创建的细节,并能提高创建的性能,说白了就是copy技术,把一个对象完整的copy出一份。
原型模式UML类图:
实现克隆方法时,调用了.NET中封装的方法MemberwiseClone()方法,该方法创建一个浅表副本,方法是创建一个新对象, 然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。
对于.NET而言原型抽象类ProtoType是用不到的,因为克隆的实用性,.NET在System的命名空间中提供了ICloneable接口,其中包含唯一的一个方法clone(),这样只需要实现这个接口就可以完成原型模式了。
原型模式的有效利用会使得项目的性能大大的提高,在所创建对象的初始化不发生变化的情况下,使用克隆技术可以大大减少构造函数的调用,对于一个比较复杂费时间的构造函数来说,使用原型模式的克隆技术可以节省大量的时间,这样便很大程度上提高了性能,同时克隆技术还隐藏了对象创建的细节。
但是我们必须了解在使用原型模式时,通过实现.NET中封装的接口IConeable,调用MemberwiseClone()方法来完成,该方法完成的是“浅拷贝”,在不涉及拷贝引用的情况下,可以达到很好的效果,然而,一旦涉及拷贝引用类型的深拷贝时,则不能达到想要的效果。
首先,区分一下“浅拷贝”和“深拷贝”的区别,“浅拷贝”是指被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。而“深拷贝”则把引用对象的变量指向复制过的新对象。而不是原有被引用的原有对象。
原型模式应用实例-简历的深复制实现:
(1)工作经历类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProtoType
{
class WorkExperience :ICloneable
{
private string startDate;
private string endDate;
private string company;
public string getStartDate()
{
return this.startDate;
}
public void setStartDate(string date)
{
this.startDate = date;
}
public string getEndDate()
{
return this.endDate;
}
public void setEndDate(string endDate)
{
this.endDate = endDate;
}
public string getCompany()
{
return this.company;
}
public void setCompany(string company)
{
this.company = company;
}
public Object Clone()
{
/*
* MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,
* 然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,
* 则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制
* 引用的对象;因此,原始对象及其复本引用同一对象。
*/
return (Object)this.MemberwiseClone();
}
}
}
(2)简历类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProtoType
{
class Resume : ICloneable
{
private string name;
private string sex;
private int age;
private WorkExperience workExperience;
public Resume(String name)
{
this.name = name;
this.workExperience = new WorkExperience();
}
public Resume(WorkExperience we)
{
this.workExperience = new WorkExperience();
this.workExperience.setStartDate(((WorkExperience)workExperience.Clone()).getStartDate());
this.workExperience.setEndDate(((WorkExperience)workExperience.Clone()).getEndDate());
this.workExperience.setCompany(((WorkExperience)workExperience.Clone()).getCompany());
}
public string getName()
{
return this.name;
}
public void setName(string name)
{
this.name = name;
}
public string getSex()
{
return this.sex;
}
public void setSex(string sex)
{
this.sex = sex;
}
public int getAge()
{
return this.age;
}
public void setAge(int age)
{
this.age = age;
}
public WorkExperience getWorkExperience()
{
return this.workExperience;
}
public void setWorkExperience(string startDate,string endDate,string company)
{
this.workExperience.setStartDate(startDate);
this.workExperience.setEndDate(endDate);
this.workExperience.setCompany(company);
}
public void display()
{
Console.WriteLine("{0} {1} {2}",this.name,this.sex,this.age);
Console.WriteLine("工作经历:{0}-{1} {2}",this.workExperience.getStartDate(),
this.workExperience.getEndDate(),this.workExperience.getCompany());
}
public Object Clone()
{
Resume resume = new Resume(this.workExperience);
resume.setName(this.name);
resume.setAge(this.age);
resume.setSex(this.sex);
return resume;
//return (Object)this.MemberwiseClone();
}
}
}
(3)客户端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProtoType
{
class Program
{
static void Main(string[] args)
{
Resume re = new Resume("Lucy");
re.setSex("女");
re.setAge(20);
re.setWorkExperience("2010","2012","百度");
Resume re2 = (Resume)re.Clone();
re2.setWorkExperience("2010","2012","谷歌");
Resume re3 = (Resume)re.Clone();
re3.setWorkExperience("2010", "2012", "微软");
re.display();
re2.display();
re3.display();
Console.Read();
}
}
}
(4)运行结果