一.引入
小菜的问题:要把简历发到多家公司,简历的份数就必须足够。
大鸟的回答:用编程来复制自己简历。
二.解决过程
① 最初的写法:
简历类:
<span style="font-family:KaiTi_GB2312;font-size:24px;">class Resume { 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); } } </span>客户端调用代码:
<span style="font-family:KaiTi_GB2312;font-size:24px;">static void Main(string[] args) { Resume a = new Resume("大鸟"); a.SetPersonalInfo("男", "29"); a.SetWorkExperience("1998-2000", "XX公司"); Resume b = new Resume("大鸟"); b.SetPersonalInfo("男", "29"); b.SetWorkExperience("1998-2000", "XX公司"); Resume c = new Resume("大鸟"); c.SetPersonalInfo("男", "29"); c.SetWorkExperience("1998-2000", "XX公司"); a.Display(); b.Display(); c.Display(); Console.Read(); }</span>这样,确实可以做到复制出多份简历,但想要修改简历,每一个实例化的简历都需要修改。这样的工作就很庞大了。
② 传引用写法:
<span style="font-family:KaiTi_GB2312;font-size:24px;">static void Main(string[] args) { Resume a = new Resume("大鸟"); a.SetPersonalInfo("男", "29"); a.SetWorkExperience("1998-2000", "XX公司"); Resume b = a; Resume c = a; a.Display(); b.Display(); c.Display(); Console.Read(); }</span>
这样,代码虽然简单了,但根本没有做到复制简历,b和c纸张上无法将a上的内容得到。
三.应用原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
创建原型类:
<span style="font-family:KaiTi_GB2312;font-size:24px;"> abstract class Prototype { private string id; public Prototype(string id) { this.id = id; } public string Id { get { return id; } } public abstract Prototype Clone();//抽象类的关键方法Clone }</span>
具体原型类:
<span style="font-family:KaiTi_GB2312;font-size:24px;">class ConcretePrototype1 : Prototype { public ConcretePrototype1(string id) : base(id) { } public override Prototype Clone() { return (Prototype)this.MemberwiseClone(); } } </span>客户端代码:
<span style="font-family:KaiTi_GB2312;font-size:24px;"> static void Main(string[] args) { ConcretePrototype1 p1 = new ConcretePrototype1("I"); ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone(); Console.WriteLine("Cloned:{0}", c1.Id); Console.Read(); }</span>利用ICloneable接口实现简历原型:
简历类:
<span style="font-family:KaiTi_GB2312;font-size:24px;">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(); } <span style="white-space:pre"> </span>}</span>客户端代码:
<span style="font-family:KaiTi_GB2312;font-size:24px;"> 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", "XX公司"); Resume c = (Resume)a.Clone(); c.SetWorkExperience("男", "24"); a.Display(); b.Display(); c.Display(); Console.Read(); } </span>四.扩展
① 浅复制:
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。这样的定义很难理解,就拿实例结果说话吧:
原本想要前图那样的效果,结果却是后图。这样一个过程也就是浅复制的过程,看似复制了,但实际上内容并没有得到复制。
② 深复制:
把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
工作经历类:
<span style="font-family:KaiTi_GB2312;font-size:24px;">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.MemberwiseClone();//“工作经历”类实现克隆方法 }</span>简历类:
<span style="font-family:KaiTi_GB2312;font-size:24px;">private Resume(WorkExperience work) { this.work = (WorkExperience)work.Clone();//提供Clone方法调用的私有构造函数,以便克隆“工作经历”的数据 }</span>
<span style="font-family:KaiTi_GB2312;font-size:24px;">public Object Clone() { Resume obj = new Resume(this.work);//调用私有的构造方法,让“工作经历”克隆完成,然后再给“简历”对象的相关字段赋值 obj.name = this.name; obj.sex = this.sex; obj.age = this.age; return obj; }</span>从而达到我们想要的结果,如下图:
五.学习心得
对于这一过程的学习,觉得原型模式很简单,生活中也很常见,只要给出一个原型的种类就行。复制简历,是一个很常见的实例,运用原型模式,也确实是最佳体现。至于后面的浅复制与深复制的学习,刚开始不知道他们想表达的是什么意思,于是从结果出发,浅复制的结果不是所想要得到的,深复制才是,这时候便去研究两者的代码,两者的结构图,才发现,其实也很简单,只要将“工作经历”这一类同样利用接口去实现,就可以达到其想要达到的效果了。