书中以简历为例,创建一个简历类,带有一些基本信息。客户端需要很多分相同的简历来投递, 就 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 }
对于 .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 }
这样一来,如果想要改某一分简历,只需要对这一份简历做一定的修改就可以惹。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 }
在一些特定场合, 会经常涉及深复制或浅复制,比如 数据集对象DataSet 它就有 Clone() 方法和 Copy() 方法, Clone() 方法用了复制 DataSet 的结构,但不复制 DataSet 的数据,实现了原型模式的浅复制。Copy() 方法不但复制结构,也复制数据,其实就是实现了原型模式的深复制。
浙公网安备 33010602011771号