C#学习笔记-原型模式

题目:编写基本的简历。

实现:

创建基本的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         }
View Code

主函数:

 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         }
View Code

 

 

 

题目延伸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     }
View Code

实现:

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();
            }
        }
View Code

主函数:

 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         }
View Code

 

 

 

题目延伸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         }
View Code

所以这就涉及到了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         }
View Code

 

 

注:文中所有代码及知识点均来自于《大话设计模式》,本人属于边学边看边敲代码边总结的阶段。

posted @ 2017-09-28 17:14  多多陪着小五  阅读(237)  评论(0编辑  收藏  举报