现在找工作求职,简历都是需要复印的。而对于编程来说,简单的复制粘贴极有可能造成重复代码的灾难。
我们要求有一个简历类,必须要有姓名,可以设置性别和年龄,可以设置工作经历。最终需要三份简历。
最容易的做法,写完类后直接 实例化三次类就行了。
但是这样做的话会很麻烦,如果要二十份,我们需要二十次实例化。并且如果写错一个字,比如98年改成99年,就需要改二十次。
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式就是从一个对象再创建另外一个可定制的对象,并且不需知道任何创建的细节。
克隆的话用到一个方法:MemberwiseClone():创建当前对象的浅表副本,方法是创建一个新对象,然后将当前对象那的非静态字段复制到该新对象,如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其副本引用同一对象。
.Net在System命名空间提供了ICloneable接口,其中就是唯一的方法Clone()。只需要实现这个接口就可以完成原型模式了。
源代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Prototype
{
class Resume : ICloneable
{
private string name;
private string sex;
private string age;
private string timeArea;
private string company;
public Resume(string name)
{
this.name = name;
}
public void SetPersonalInfo(string sex, string age)
{
this.sex = sex;
this.age = age;
}
public void SetWorkExperience(string timeArea, string company)
{
this.timeArea = timeArea;
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();
}
}
class Program
{
static void Main(string[] args)
{
Resume a = new Resume("大鸟");
a.SetPersonalInfo("男", "29");
a.SetWorkExperience("1998-2000", "XX公司");
Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006", "YY企业");
Resume c = (Resume)a.Clone();
c.SetPersonalInfo("男", "24");
a.Display();
b.Display();
c.Display();
Console.Read();
}
}
}
一般在初始化的细腻些不发生变化的情况下,克隆是最好的办法,这样既隐藏了对象创建的细节,有对性能是大大的提高。
不用重新初始化对象,而是动态的获得对象运行时的状态。
如果简历中有一个工作经历类,当中有时间区间和公司名称等属性,简历类直接点调用这个对象即可。
这时就出现问题了,浅复制对于引用类型,只是复制了引用,对引用的对象还是指向了原来的对象,所以就会出现个a,b,c三个引用设置工作经历,但却同时看到三个引用都是最后一次设置,因为三个都指向了同一个对象。
这就是浅复制,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
我们有事需要把复制的对象所引用的对象都复制一遍。
深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Prototype
{
//工作经历
class WorkExperience : 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.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(); //在简历类实例化时同时实例化工作经历
}
public 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 timeArea, string company)
{
//调用此方法时,给对象的两属性赋值
work.WorkDate = timeArea;
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 = name;
obj.sex = sex;
obj.age = age;
return obj;
}
}
class Program
{
static void Main(string[] args)
{
Resume a = new Resume("大鸟");
a.SetPersonalInfo("男", "29");
a.SetWorkExperience("1998-2000", "XX公司");
//b和c都克隆于a,但当它们都设置了工作经历时,我们希望的结果是三个的显示不一样。
Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006", "YY企业");
Resume c = (Resume)a.Clone();
c.SetPersonalInfo("男", "24");
c.SetWorkExperience("1998-2003", "ZZ企业");
a.Display();
b.Display();
c.Display();
Console.Read();
}
}
}
由于在一些特定场合,会经常涉及到深复制或浅复制,比如说,数据集对象DataSet,它就有Clone()方法和Copy()方法,Clone()方法用来复制DataSet的结构,但不复制Dataset的数据,实现了原型模式的浅复制,Copy()方法不但复制结构,也复制数据,起始就是实现了原型模式的深复制。