C#设计模式-2创建型模式-2.6原型模式(Prototype Pattern)


2.6.1 定义

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

2.6.2 场景模拟

写一个简历类,必须要有姓名,可以设置性别和年龄,可以设置工作经历,最终需要三份简历。

2.6.3 代码演示

class Program
    {
        static void Main(string[] args)
        {
            Resume resume1 = new Resume("hobe");
            resume1.SetPersonalInfo("", 35);
            resume1.SetWorkExperience("2009-2014","XX公司");

            Resume resume2 = (Resume)resume1.Clone();
            resume2.SetWorkExperience("2014-2016","YY公司");

            Resume resume3 = (Resume)resume1.Clone();
            resume3.SetPersonalInfo("", 32);

            resume1.Display();
            resume2.Display();
            resume3.Display();
            Console.ReadLine();
        }
    }

    public class Resume : ICloneable
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }
        public string TimeArea { get; set; }
        public string Company { get; set; }
        public Resume(string name)
        {
            this.Name = name;
        }

        public void SetPersonalInfo(string sex,int 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($"{Name} {Sex} {Age.ToString()}");
            Console.WriteLine($"工作经历:{TimeArea} {Company}");
        }
        public object Clone()
        {
            return this.MemberwiseClone();
        }
}

       上面代码实现的浅拷贝的方式,浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么这两个对象将引用同一个字符串,而深拷贝是对对象实例中字段引用的对象也进行拷贝,如果一个对象有一个指向字符串的字段,并且我们对该对象进行了深拷贝的话,那么我们将创建一个对象和一个新的字符串,新的对象将引用新的字符串。也就是说,执行深拷贝创建的新对象和原来对象不会共享任何东西,改变一个对象对另外一个对象没有任何影响,而执行浅拷贝创建的新对象与原来对象共享成员,改变一个对象,另外一个对象的成员也会改变。

     

深复制的应用场景:

加一个工作经历类,这个类中有时间区间和公司名称,简历类中直接调用这个对象

using System;

namespace PrototypePattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Resume resume1 = new Resume("hobe");
            resume1.SetPersonalInfo("", 35);
            resume1.SetWorkExperience("2009-2014","XX公司");

            Resume resume2 = (Resume)resume1.Clone();
            resume2.SetWorkExperience("2014-2016","YY公司");

            Resume resume3 = (Resume)resume1.Clone();
            resume3.SetWorkExperience("2014-2016", "ZZ公司");

            resume1.Display();
            resume2.Display();
            resume3.Display();
            Console.ReadLine();
        }
    }

    public class WorkExperience : ICloneable
    {
        public string WorkDate { get; set; }
        public string Company { get; set; }
        public object Clone()
        {
            return this.MemberwiseClone();
        }
    }
    public class Resume : ICloneable
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }
        public WorkExperience Work { get; set; }
        public Resume(string name)
        {
            this.Name = name;
            this.Work = new WorkExperience();
        }
        private Resume(WorkExperience work)
        {
            this.Work = (WorkExperience)work.Clone();
        }
        public void SetPersonalInfo(string sex,int age)
        {
            this.Sex = sex;
            this.Age = age;
        }
        public void SetWorkExperience(string workDate,string company)
        {
            Work.WorkDate = workDate;
            Work.Company = company;
        }

        public void Display()
        {
            Console.WriteLine($"{Name} {Sex} {Age.ToString()}");
            Console.WriteLine($"工作经历:{Work.WorkDate} {Work.Company}");
        }
        public object Clone()
        {
            Resume resume = new Resume(this.Work);
            resume.Name = this.Name;
            resume.Sex = this.Sex;
            resume.Age = this.Age;
            return resume;
        }
    }
}

2.6.4 优缺点

优点:

原型模式向客户隐藏了创建新实例的复杂性

原型模式允许动态增加或较少产品类。

原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。

产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构

缺点:

每个类必须配备一个克隆方法

配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。