原型模式(Prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节 。
原型类 Prototype:
- abstract class Prototype
- {
- private string id;
-
- public Prototype(string id)
- {
- this.id = id;
- }
- public string Id
- {
- get { return id; }
- }
- //抽象类关键有这样一个Clone方法
- public abstract Prototype Clone();
- }
ConcretePrototypel类,具体原型
- class ConcretePrototypel : Prototype
- {
- public ConcretePrototypel(string id) : base(id) { }
- public override Prototype Clone()
- {
- //创建一个新对象,然后将当前对象非静态字段复制到该新对象
- //如果字段是值类型,则逐位复制字段,引用类型只复制引用地址
- return (Prototype)this.MemberwiseClone();
- }
- }
客户端:
- class Main : MonoBehaviour
- {
- private void Start()
- {
- ConcretePrototypel pl = new ConcretePrototypel("I");
- ConcretePrototypel cl = (ConcretePrototypel)pl.Clone();
- Debug.Log("clone" + cl.Id);
-
- }
- }
由于克隆实在太常用,.Net在System命名空间提供了IClone接口,唯一的Clone()方法,只要实现这个接口就可以完成原型模式了。
简历类:
- 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 SetWorkExperrience(string timeArea,string company)
- {
- this.timearea = timeArea;
- this.company = company;
- }
-
- //显示
- public void Display()
- {
- //实现接口方法,克隆对象
- Debug.Log(name + " " + sex + " " + age);
- Debug.Log(timearea + " " + company);
- }
- public object Clone()
- {
- return (object)this.MemberwiseClone();
- }
- }
客户端:
- class Main : MonoBehaviour
- {
- private void Start()
- {
- Resume a = new Resume("DJ");
- a.SetPersonalInfo("男", "22");
- a.SetWorkExperrience("1995-2022", "DJDJ");
-
- //调用克隆方法就可以实现新简历,并且可以修改新简历细节
- Resume b = (Resume)a.Clone();
- b.SetPersonalInfo("nv", "20");
-
- Resume c = (Resume)a.Clone();
- c.SetWorkExperrience("1999-2222", "JJJJ");
-
- a.Display();
- b.Display();
- c.Display();
- }
- }
输出结果:
现实设计当中,一般会再有一个“工作经历”类,当中有“时间区间”和“公司名称”等属性,“简历”类直接调用。
- class Resume : ICloneable
- {
- private string name;
- private string sex;
- private string age;
- private WorkExperience work;///引用“工作经历”对象
-
- public Resume(string name)
- {
- this.name = name;
- work = new WorkExperience();//简历实例化同时实例化工作经历
- }
-
- public void SetPersonalInfo(string sex,string age)
- {
- this.sex = sex;
- this.age = age;
- }
-
- public void SetWorkExperrience(string workDate,string company)
- {
- work.WorkDate = workDate;//调用方法,给对象赋值
- work.Company = company;
- }
-
- public void Display()
- {
-
- Debug.Log(name + " " + sex + " " + age);
- Debug.Log(work.WorkDate + " " + work.Company);//显示工作经历属性值
- }
- public object Clone()
- {
- return (object)this.MemberwiseClone();
- }
- }
- class WorkExperience
- {
- private string workDate;
- public string WorkDate
- {
- get { return workDate; }
- set { workDate = value; }
- }
- private string company;
- public string Company
- {
- get { return company; }
- set { company = value; }
- }
- }
使用之前的客户端逻辑,运行后结果:
对于引用类型,克隆后没有实现真正的克隆,而是只克隆了引用地址,这叫做“浅复制”,被复制对象的所有变量都含有与原来的对象相同的值;而所有的对其他对象的引用都仍然指向原来的对象。
深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
深复制流程:
首先修改WorkExperience类,增加克隆方法
- class WorkExperience
- {
- 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)MemberwiseClone();
- }
- }
然后修改简历类,新增构造函数,方便克隆工作经历类,再修改简历类的克隆方法
- class Resume : ICloneable
- {
- private string name;
- private string sex;
- private string age;
- private WorkExperience work;
-
- public Resume(string name)
- {
- this.name = name;
- work = new WorkExperience();
- }
- //提供Clone方法调用的私有构造函数,以便克隆工作经历数据
- public Resume(WorkExperience work)
- {
- this.work = (WorkExperience)work.Clone();
- }
- public void SetPersonalInfo(string sex,string age)
- {
- this.sex = sex;
- this.age = age;
- }
- public void SetWorkExperrience(string workDate,string company)
- {
- work.WorkDate = workDate;
- work.Company = company;
- }
- public void Display()
- {
- Debug.Log(name + " " + sex + " " + age);
- Debug.Log(work.WorkDate + " " + work.Company);
- }
-
- //调用私有构造方法,让工作经历克隆,然后再给新对象其他字段赋值
- //最终返回一个深复制的简历对象
- public object Clone()
- {
- Resume obj = new Resume(this.work);
- obj.name = this.name;
- obj.sex = this.sex;
- obj.age = this.age;
- return obj;
- }
- }
还是使用之前的客户端逻辑,结果如下。