书中以简历为例,创建一个简历类,带有一些基本信息。客户端需要很多分相同的简历来投递, 就 new 出了很多份简历并赋值基本信息。 这样的坏处在于如果发现简历某个东西写错了,就要全部推翻来重写。

原型模式好处是 如果有一个类有123三条属性,完全可以new一个类出来赋值123的属性,然后clone这个类并有针对的去修改123的值,不做修改的沿用原有值。

原型  n. prototype ; archetype  英 ['prəʊtətaɪp]  美 ['protə'taɪp] 

 

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class PrototypeStufdy : MonoBehaviour {
 5 
 6     // Use this for initialization
 7     void Start () {
 8         ConcretePrototype p1 = new ConcretePrototype("I");
 9         ConcretePrototype c1 = (ConcretePrototype) p1.Clone();
10     }
11 }
12 
13 //抽象一个原型类
14 public  abstract class Prototype
15 {
16     private string id;
17 
18     public Prototype(string id)
19     {
20         this.id = id;
21     }
22 
23     public string ID
24     {
25         get { return id; }
26     }
27 
28     //抽象类关键在于这个 Clone 方法
29     public abstract Prototype Clone();
30 }
31 //具体原型类
32 class  ConcretePrototype  : Prototype
33 {
34     public ConcretePrototype(string id) : base(id)
35     {
36     }
37 
38     public override Prototype Clone()
39     {
40         return (Prototype)this.MemberwiseClone();
41         /*
42          创建当前对象的浅表副本。方法是创建一个新对象,然后将当前对象的非静态字段(静态的话 大家同传的
43          * 一条裤子)复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型的,
44          * 则复制引用但不复制引用的对象;因此,原始对象及其副本引用同一对象
45          */
46     }
47 }
View Code

 

对于 .NET 而言,那个原型抽象类 Prototype 是用不着的,因为克隆实在太常用了,所以 .NET 在 System 命名空间中提供了 ICloneable 接口, 其中就是唯一的一个方法 Clone()。这样我们只需要实现这个接口就可以完成原型模式了。

 

例:

 

 1 using UnityEngine;
 2 using System.Collections;
 3 using System;
 4 
 5 public class Example2 : MonoBehaviour {
 6     // Use this for initialization
 7     void Start () {
 8         Resume a = new Resume();
 9         a.SetInfo(10,"小王");
10         a.SetComponent("SM公司","哈士奇");
11         //这个时候在需要一个 跟小王信息相近 或者 差别不大的对象就好办了 不用重新new一个
12         Resume b = (Resume) a.Clone();
13         b.SetInfo(30,"老王");
14 
15         Resume c = (Resume)a.Clone();
16         c.SetComponent("Super公司","贵妇");
17         //这样 b 与 c 的未设置的信息实际上是clone 了a的信息。而且并不是a的引用
18 
19         a.Display();//小王 ,年龄:10, 公司:SM公司, 备注:哈士奇
20         b.Display();//老王 ,年龄:30, 公司:SM公司, 备注:哈士奇
21         c.Display();//小王 ,年龄:10, 公司:Super公司, 备注:贵妇
22     }
23 }
24 
25 public class Resume : ICloneable
26 {
27      string name;
28      int age;
29      string compony;
30      string component;
31     public void SetInfo(int age,string name)
32     {
33         this.name = name;
34         this.age = age;
35     }
36     public void SetComponent(string compony,string component)
37     {
38         this.compony = compony;
39         this.component = component;
40     }
41 
42     public void Display()
43     {
44         Debug.Log(string.Format("{0} ,年龄:{1}, 公司:{2}, 备注:{3}",name,age,compony,component));
45     }
46 
47     // 核心方法!!!!
48     public object Clone()
49     {
50 //        return (object) this; 注意不要写错 - - 返回了这个类的引用
51         return (object) this.MemberwiseClone();
52     }
53 }
View Code

 

 这样一来,如果想要改某一分简历,只需要对这一份简历做一定的修改就可以惹。233333.。 原来的 没一次 new 都需要执行一次构造函数,如果构造函数的执行时间很长,那么多次执行这个初始化操作就实在是太低效了。一般在初始化的信息不发生变化的情况下,克隆是最好的办法。这即隐藏了对象创建的细节,又对性能是大大的提升。 等于是不同重新初始化对象,而是动态地获得对象运行时的状态。

存在问题:

浅复制与深复制

MemberwiseClone() 方法是这样子的,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象:因此,原始对象及其复本引用同一对象。

比方原有类中有一个字段是另一个类,那么clone出来的所有类,对这个类的引用都是同一个,改一个其他的也都全变了。哈哈哈哈 这TM的就叫做浅复制,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

深复制就相反,把引用的对象的变量指向复制过的新对象,而不是原有的被引用的对象。

 使用时要考虑深复制要深入多少层,而且要当心出现循环引用的问题。

 

 1 using UnityEngine;
 2 using System.Collections;
 3 using System;
 4 
 5 public class Example2 : MonoBehaviour {
 6     // Use this for initialization
 7     void Start () {
 8         Resume a = new Resume();
 9         a.SetInfo(10,"小王");
10         a.SetComponent("SM公司","哈士奇");
11         //这个时候在需要一个 跟小王信息相近 或者 差别不大的对象就好办了 不用重新new一个
12         Resume b = (Resume) a.Clone();
13         b.SetInfo(30,"老王");
14 
15         Resume c = (Resume)a.Clone();
16         c.SetComponent("Super公司","贵妇");
17         //这样 b 与 c 的未设置的信息实际上是clone 了a的信息。而且并不是a的引用
18 
19         a.Display();//小王 ,年龄:10, 公司:SM公司, 备注:哈士奇
20         b.Display();//老王 ,年龄:30, 公司:SM公司, 备注:哈士奇
21         c.Display();//小王 ,年龄:10, 公司:Super公司, 备注:贵妇
22     }
23 }
24 
25 public class WorkExperience : ICloneable
26 {
27     public object Clone()
28     {//类中存在的引用 也要实现这个接口 实现克隆方法
29         return (object) this.MemberwiseClone();
30     }
31 }
32 
33 public class Resume : ICloneable
34 {
35     private string name;
36     private int age;
37     private string compony;
38     private string component;
39     private WorkExperience wor;
40     public void SetInfo(int age, string name)
41     {
42         this.name = name;
43         this.age = age;
44     }
45 
46     public void SetComponent(string compony, string component)
47     {
48         this.compony = compony;
49         this.component = component;
50     }
51 
52     public Resume(WorkExperience wor)
53     {
54         this.wor = (WorkExperience) wor.Clone();//clone 工作经历
55     }
56 public void Display()
57     {
58         Debug.Log(string.Format("{0} ,年龄:{1}, 公司:{2}, 备注:{3}",name,age,compony,component));
59     }
60 
61     // 核心方法!!!!
62     public object Clone()
63     {
64         Resume obj = new Resume(this.wor);
65         obj.name = this.name;
66         obj.age = this.age;
67         obj.component = this.component;
68         obj.compony = this.compony;
69         return obj;
70     }
71 }
View Code

 

在一些特定场合, 会经常涉及深复制或浅复制,比如 数据集对象DataSet 它就有 Clone() 方法和 Copy() 方法, Clone() 方法用了复制 DataSet 的结构,但不复制 DataSet 的数据,实现了原型模式的浅复制。Copy() 方法不但复制结构,也复制数据,其实就是实现了原型模式的深复制。

 

posted on 2017-09-07 16:34  Mr.糖马儒  阅读(156)  评论(0)    收藏  举报