Unity设计模式——原型模式

原型模式 (Prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节 。

原型类 Prototype:

cs 复制代码
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类,具体原型

cs 复制代码
class ConcretePrototypel : Prototype
{
    public ConcretePrototypel(string id) : base(id) { }
    public override Prototype Clone()
    {
        //创建一个新对象,然后将当前对象非静态字段复制到该新对象
        //如果字段是值类型,则逐位复制字段,引用类型只复制引用地址
        return (Prototype)this.MemberwiseClone();
    }
}

客户端:

cs 复制代码
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()方法,只要实现这个接口就可以完成原型模式了。

简历类:

cs 复制代码
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();
    }
}

客户端:

cs 复制代码
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();
    }
}

输出结果:

现实设计当中,一般会再有一个"工作经历"类,当中有"时间区间"和"公司名称"等属性,"简历"类直接调用。

cs 复制代码
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类,增加克隆方法

cs 复制代码
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();
    }
}

然后修改简历类,新增构造函数,方便克隆工作经历类,再修改简历类的克隆方法

cs 复制代码
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;
    }
}

还是使用之前的客户端逻辑,结果如下。

相关推荐
小白不太白9501 小时前
设计模式之 观察者模式
观察者模式·设计模式
小白不太白9502 小时前
设计模式之 责任链模式
python·设计模式·责任链模式
何大春3 小时前
【弱监督语义分割】Self-supervised Image-specific Prototype Exploration for WSSS 论文阅读
论文阅读·人工智能·python·深度学习·论文笔记·原型模式
吾与谁归in3 小时前
【C#设计模式(13)——代理模式(Proxy Pattern)】
设计模式·c#·代理模式
吾与谁归in3 小时前
【C#设计模式(14)——责任链模式( Chain-of-responsibility Pattern)】
设计模式·c#·责任链模式
闲人一枚(学习中)3 小时前
设计模式-创建型-原型模式
设计模式
Iced_Sheep3 小时前
干掉 if else 之策略模式
后端·设计模式
哪 吒11 小时前
最简单的设计模式,抽象工厂模式,是否属于过度设计?
设计模式·抽象工厂模式
Theodore_102211 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
转世成为计算机大神14 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式