设计模式之笔记--原型模式(Prototype)


原型模式(Prototype)

定义

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

类图

描述

提供一个克隆自身的接口--Clone方法。

应用场景

定义一个学生类,包含一个值类型(int)的Age属性、两个引用类型Name(string)和Course属性。

    public class Course
    {
        public string Name { get; set; }
    }

    public abstract class AbstractStudent
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Course Course { get; set; }

        public abstract AbstractStudent Clone();
    }

    /// 
    /// 浅拷贝
    /// 
    public class Student : AbstractStudent
    {
        public override AbstractStudent Clone()
        {
            Student student = new Student();
            student.Name = base.Name;
            student.Age = base.Age;
            student.Course = base.Course;

            return student;
        }
    }

输出:

student : Jim 20 C++

student : Jim 20 C#
student1: Tom 21 C#

student : Jim 20 Java
student1: Tom 21 Java

      从打印的结果可以看出,给原对象student拷贝一个新的student1对象并给student1属性赋值之后,原对象student的Age和Name没变,CourseName却变了。原因是拷贝之后,student把student1的Age和Name复制了一份,而student1的Course依然指向student的Course地址,所以,当student1的CourseName改变时,student的CourseName也随之改变,这就是浅拷贝。

      但是在实际应用中,往往不希望发生这样的事情,也就是不能因为拷贝对象发生变化而影响到原对象。原因很简单,不能因为Tom选了C#这门课就要求Jim也必须把已经选的C++这门课改成C#。要解决这个问题,就需要拷贝一个全新的对象,即深拷贝。

下面通过序列化和反序列化来创建一个全新的student:

    [Serializable]
    public class Course
    {
        public string Name { get; set; }
    }

    [Serializable]
    public abstract class AbstractStudent
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Course Course { get; set; }

        public abstract AbstractStudent Clone();
    }

    [Serializable]
    /// 
    /// 深拷贝
    /// 
    public class Student : AbstractStudent
    {
        public override AbstractStudent Clone()
        {
            using (Stream objectStream = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, this);
                objectStream.Seek(0, SeekOrigin.Begin);
                return formatter.Deserialize(objectStream) as Student;
            }
        }
    }

输出:

student : Jim 20 C++

student : Jim 20 C++
student1: Tom 21 C#

student : Jim 20 C++
student1: Tom 21 Java

浅拷贝和深拷贝的区别:

浅拷贝:对值类型和string类型直接拷贝,对引用类型共用同一个指针;两个对象之间存在耦合;

深拷贝:给对象拷贝一个全新的对象,两个对象之间的耦合度为0。