题目:编写基本的简历。
实现:
创建基本的Resume类,然后主函数通过实例化Resume来写简历即可。
Resume类:
1 class Resume 2 { 3 private string name; 4 private string sex; 5 private string age; 6 private string timeArea; 7 private string company; 8 9 public Resume(string name) 10 { 11 this.name = name; 12 } 13 14 //设置个人信息 15 public void SetPersonalInfo(string sex,string age) 16 { 17 this.age = age; 18 this.sex = sex; 19 } 20 21 public void SetWorkExperience(string timeArea,string company) 22 { 23 this.timeArea = timeArea; 24 this.company = company; 25 } 26 27 public void Show() 28 { 29 Console.WriteLine("{0} {1} {2} ", name, sex, age); 30 Console.WriteLine("工作经历:{0} {1} ", timeArea, company); 31 } 32 }
主函数:
1 static void Main(string[] args) 2 { 3 //每写一份简历就实例化一次Resume,写一百分相同的简历也要实例化一百次 4 //且如果写错了一个词就得修改同样次数的简历 5 Resume a = new Resume("Taylor"); 6 a.SetPersonalInfo("女", "28"); 7 a.SetWorkExperience("1999-2008", "QWE"); 8 a.Show(); 9 10 Resume b = new Resume("Selena"); 11 b.SetPersonalInfo("女", "28"); 12 b.SetWorkExperience("1999-2008", "MNB"); 13 b.Show(); 14 15 //Console.Read(); 16 17 //这是传引用,而不是传值,这样如同在c1和b1的纸张上写着:简历在a1处,并没有实际的内容 18 Resume a1 = new Resume("Taylor"); 19 a1.SetPersonalInfo("女", "28"); 20 a1.SetWorkExperience("1999-2008", "QWE"); 21 a1.Show(); 22 23 Resume b1 = a1; 24 Resume c1 = a1; 25 26 b1.Show(); 27 c1.Show(); 28 29 Console.Read(); 30 }
题目延伸1:如果我们现在批量打印简历,如果用上面的方法就得每写一份简历都得实例化一次,且如果简历的某种信息输入错误,那么我们就得修改同样次数的简历,这就使工作量变得巨大了。
解析:
这时我们就需要引进原型模式(Prototype)
原型模式(Prototype),用原型实例指定创建对象的种类,并且 通过拷贝这些原型创建新的对象。
原型模式的范例:(这个例子是书上看来的,敲完了,看完了,还是理解的不是特别清楚,我的理解还是比较适合实例一点,这个真的看得无力......)
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 ConcretePrototypel p1 = new ConcretePrototypel("I"); 6 ConcretePrototypel c1 = (ConcretePrototypel)p1.Clone(); 7 Console.WriteLine("Cloned: {0}", c1.Id); 8 9 ConcretePrototypel2 p2 = new ConcretePrototypel2("II"); 10 ConcretePrototypel2 c2 = (ConcretePrototypel2)p2.Clone(); 11 Console.WriteLine("Cloned: {0}", c2.Id); 12 13 // Wait for user 14 Console.Read(); 15 16 } 17 } 18 19 //原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。 20 abstract class Prototype 21 { 22 private string id; 23 24 public Prototype(string id) 25 { 26 this.id = id; 27 } 28 29 public string Id 30 { 31 get 32 { 33 return id; 34 } 35 } 36 37 public abstract Prototype Clone(); 38 } 39 40 41 class ConcretePrototypel:Prototype 42 { 43 public ConcretePrototypel(string id):base(id) 44 { 45 } 46 47 public override Prototype Clone() 48 { 49 //创建当前对象的浅表副本。方法是创建一个新对象,然后将当前对象的 50 //非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。 51 //如果字段是引用类型,则复制引用但不复制引用的对象。 52 //因此,原始对象及副本引用同一对象。 53 return (Prototype)this.MemberwiseClone(); 54 } 55 } 56 57 58 class ConcretePrototypel2 : Prototype 59 { 60 public ConcretePrototypel2(string id) : base(id) 61 { 62 } 63 64 public override Prototype Clone() 65 { 66 // 67 // 摘要: 68 // 创建当前 System.Object 的浅表副本。 69 // 70 // 返回结果: 71 // 当前 System.Object 的浅表副本。 72 return (Prototype)this.MemberwiseClone(); 73 } 74 }
实现:
Resume类:
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); } public object Clone() { /** * MemberwiseClone()方法: * 如果字段是值类型,则对该字段执行逐位复制, * 如果字段是引用类型,则复制引用但不复制引用的对象 * 因此,原始对象及其复本引用同一对象 * * 换句话就是, * 如果Resume中有对象引用,那么引用的对象数据是不会被克隆过来的 */ return (object)this.MemberwiseClone(); } }
主函数:
1 static void Main(string[] args) 2 { 3 /**一般在初始化的信息不发生变化的情况下, 4 * 克隆是最好的办法 5 * 这既隐藏了对象创建的细节,又对性能是大大的提高 6 * 7 * 不用重新初始化对象,而是动态地获取对象运行时的状态 8 */ 9 Resume a = new Resume("taylor"); 10 a.SetPersonalInfo("女", "28"); 11 a.SetWorkExperience("1999-2008", "YUT"); 12 13 Resume b = (Resume)a.Clone(); 14 b.SetWorkExperience("1998-2006", "RTE"); 15 16 Resume c = (Resume)a.Clone(); 17 c.SetPersonalInfo("男", "30"); 18 19 a.Display(); 20 b.Display(); 21 c.Display(); 22 23 Console.Read(); 24 }
题目延伸2:如果在简历中设置一个“工作经历”类,其中包括“时间区间”和“公司名称”等属性,简历直接调用这个对象即可。
解析:
如果按照正常的方式书写就会发现,中途如果修改了工作经历的信息,那么所有的简历工作经历都变成了最后一次修改的信息。
对于工作经历里的参数而言,他们属于静态的参数值,故此他们的最后显示会根据最后的输入值。
1 static void Main(string[] args) 2 { 3 Resume a = new Resume("Taylor"); 4 a.SetPersonalInfo("28", "女"); 5 a.SetWorkExperience("1999-2008", "UIO"); 6 7 Resume b = (Resume)a.Clone(); 8 b.SetWorkExperience("1990-2000", "QWE"); 9 b.SetPersonalInfo("24", "男"); 10 11 Resume c = (Resume)a.Clone(); 12 c.SetPersonalInfo("30", "男"); 13 c.SetWorkExperience("1000-2000", "QWE"); 14 //最后c的将work.WorkDate设置为了"1000-2000",work.Company设置为了"QWE" 15 //故此b的工作经历显示也如同c一般了,a也同理 16 //==>“浅复制” 17 18 a.Display(); 19 b.Display(); 20 c.Display(); 21 22 Console.Read(); 23 } 24 25 class Resume:ICloneable 26 { 27 private string name; 28 private string sex; 29 private string age; 30 31 private WorkExperience work; 32 33 34 public Resume(string name) 35 { 36 this.name = name; 37 work = new WorkExperience();//实例化 38 } 39 40 public void SetPersonalInfo(string age,string sex) 41 { 42 this.age = age; 43 this.sex = sex; 44 } 45 46 public void SetWorkExperience(string timeArea,string company) 47 { 48 work.WorkDate = timeArea; 49 work.Company = company; 50 51 } 52 53 public void Display() 54 { 55 Console.WriteLine("{0} {1} {2}", name, sex, age); 56 Console.WriteLine("工作经历:{0} {1}", work.WorkDate, work.Company); 57 } 58 59 public object Clone() 60 { 61 return (object)this.MemberwiseClone(); 62 } 63 } 64 65 class WorkExperience 66 { 67 private string workDate; 68 69 public string WorkDate 70 { 71 get 72 { 73 return workDate; 74 } 75 76 set 77 { 78 workDate = value; 79 } 80 } 81 82 private string company; 83 84 public string Company 85 { 86 get 87 { 88 return company; 89 } 90 91 set 92 { 93 company = value; 94 } 95 } 96 }
所以这就涉及到了MemberwiseClone()方法,“浅复制”和“深复制”问题了。
MemberwiseClone():如果字段是值类型,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其副本引用同意对象。
=>换句话就是,简历中所包含的对象引用,其引用的对象数据是不会被克隆过来的。
MemberwiseClone()就是“浅复制”:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
“深复制”:把引用对象的变量指向复制过的新对象,而不是原来的被引用的对象。
实现:
1 class Resume:ICloneable 2 { 3 private string name; 4 private string age; 5 private string sex; 6 7 private WorkExperience work; 8 public Resume(string name) 9 { 10 this.name = name; 11 work = new WorkExperience(); 12 } 13 14 /// <summary> 15 /// 私有函数 16 /// 将工作经历克隆过来 17 /// </summary> 18 /// <param name="work"></param> 19 private Resume(WorkExperience work) 20 { 21 this.work = (WorkExperience)work.Clone(); 22 } 23 24 public void SetPersonalInfo(string age,string sex) 25 { 26 this.age = age; 27 this.sex = sex; 28 } 29 30 public void SetWorkExperience(string workDate,string company) 31 { 32 work.Company = company; 33 work.WorkDate = workDate; 34 } 35 36 public void Display() 37 { 38 Console.WriteLine("{0} {1} {2}", name, sex, age); 39 Console.WriteLine("工作经历:{0} {1}", work.WorkDate, work.Company); 40 } 41 42 43 public object Clone() 44 { 45 //调用私有的构造方法,让“工作经历”克隆完成 46 //然后再给这个“简历”对象的相关字段赋值 47 //最终返回一个深复制的简历对象 48 Resume obj = new Resume(this.work); 49 obj.name = this.name; 50 obj.sex = this.sex; 51 obj.age = this.age; 52 53 return obj; 54 } 55 } 56 57 class WorkExperience : ICloneable 58 { 59 private string workDate; 60 private string company; 61 62 public string WorkDate 63 { 64 get 65 { 66 return workDate; 67 } 68 69 set 70 { 71 workDate = value; 72 } 73 } 74 75 public string Company 76 { 77 get 78 { 79 return company; 80 } 81 82 set 83 { 84 company = value; 85 } 86 } 87 88 public object Clone() 89 { 90 return (object)this.MemberwiseClone(); 91 } 92 }
注:文中所有代码及知识点均来自于《大话设计模式》,本人属于边学边看边敲代码边总结的阶段。