C#设计模式:原型模式(Prototype)及深拷贝、浅拷贝

原型模式(Prototype)

定义:

原型模式:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。被复制的实例被称为原型,这个原型是可定制的。

Prototype Pattern也是一种创建型模式,它关注的是大量相同或相似对象的创建问题。应用原型模式就是建立一个原型,然后通过对原型来进行复制的方法,来产生一个和原型相同或相似的新对象,或者说用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

模式中的角色

抽象原型类(Abstract Prototype):提供一个克隆接口

具体原型类(Concrete Prototype): 实现了克隆接口的具体原型类

原型模式的优点有:

    1. 原型模式向客户隐藏了创建新实例的复杂性和具体的产品类,减少了客户知道的名字的数目。
    2. 原型模式允通过注册原型实例就可以将一个具体产品类并入到系统中,客户可以在运行时刻建立和删除原型。
    3. 减少了子类的构造。原型模式是Clone一个原型而不是请求工厂方法创建一个,所以它不需要一个与具体产品类平行的Creator类层次。
    4. 产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构。
    5. 原型模式具有给一个应用软件动态加载新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响旧系统。

原型模式的缺点有:

原型模式的最重要缺点就是每一个类必须配备一个Clone方法,而且这个Clone方法需要对类的功能进行通盘考虑。这对全新的类来说不是很难,但对已有的类进行改造时,不一定是容易的事。

原型模式可以适用于以下情形:

    1. 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等;
    2. 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式;
    3. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用;
    4. 当一个系统应该独立于它的产品创建、构成和表示时;
    5. 当要实例化的类是在运行时刻指定时,例如通过动态装载来创建一个类;
    6. 为了避免创建一个与产品类层次平行的工厂类层次时;
    7. 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并Clone它们可能比每次用合适的状态手工实例化该类更方便一些。

浅拷贝与深拷贝

浅度复制(Shallow Copy):将原来对象中的所有字段逐个复制到一个新对象,如果字段是值类型,则简单地复制一个副本到新对象,改变新对象的值类型字段不会影响原对象;如果字段是引用类型,则复制的是引用,改变目标对象中引用类型字段的值将会影响原对象。

深度复制(Deep Copy):与浅复制不同之处在于对引用类型的处理,深复制将新对象中引用类型字段指向复制过的新对象,改变新对象中引用的任何对象,不会影响到原来的对象中对应字段的内容。

值类型和引用类型的知识点可以了解:值类型和引用类型深入理解

浅拷贝与深拷贝示例:

拷贝对象School和Student:

    [Serializable]
    public class Student : ICloneable
    {
        private string name = "xxx";
        private int age = 0;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public int Age
        {
            get { return age; }
            set { age = value; }
        }

        /// <summary>
        /// 新建对象实现克隆
        /// </summary>
        /// <returns></returns>
        public Student NewClone()
        {
            return new Student() { age = this.age, name = this.name };
        }

        /// <summary>
        /// 实现ICloneable接口
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            return this.MemberwiseClone();
        }
    }

    [Serializable]
    public class School : ICloneable
    {
        private string m_Name = "init";
        private int m_Number = -1;
        private Student m_Student;

        public string Name
        {
            get { return m_Name; }
            set { m_Name = value; }
        }

        public int Number
        {
            get { return m_Number; }
            set { m_Number = value; }
        }

        public Student Student
        {
            get { return m_Student; }
            set { m_Student = value; }
        }

        /// <summary>
        /// 新建对象实现克隆,如果属性是引用类型,需要一层层new赋值,直到属性是值类型为止
        /// </summary>
        /// <returns></returns>
        public School NewClone()
        {
            return new School()
            {
                m_Name = this.m_Name,
                m_Number = this.Number,
                Student = this.Student.NewClone()
            };
        }

        /// <summary>
        /// 实现ICloneable接口
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            return this.MemberwiseClone();
        }
    }

序列化拷贝和反射拷贝:

     public static class HelperTools
    {
        /// <summary>
        /// 序列化深拷贝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T SerializableClone<T>(T source)
        {
            if (!typeof(T).IsSerializable)
            {
                throw new ArgumentException("The type must be serializable.", source.GetType().ToString());
            }
            if (Object.ReferenceEquals(source, null))
            {
                return default(T);
            }
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, source);
                ms.Seek(0, SeekOrigin.Begin);
                return (T)formatter.Deserialize(ms);
            }
        }

        /// <summary>
        /// 反射属性浅拷贝
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T PropertyClone<T>(T t)
        {
            if (Object.ReferenceEquals(t, null))
            {
                return default(T);
            }
            Type type = t.GetType();
            PropertyInfo[] propertyInfos = type.GetProperties();
            Object obj = Activator.CreateInstance<T>();
            Object p = type.InvokeMember("", BindingFlags.CreateInstance, null, t, null);
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (propertyInfo.CanWrite)
                {
                    object value = propertyInfo.GetValue(t, null);
                    propertyInfo.SetValue(obj, value, null);
                }
            }
            return (T)obj;
        }
    }
     public class Program
    {
        static void Main(string[] args)
        {
            School school = new School()
            {
                Name = "德源小学",
                Number = 0,
                Student = new Student()
                {
                    Name = "兔基斯",
                    Age = 18
                }
            };
            Console.WriteLine("************************原始值*****************************");
            ShowSchoolInfo(school);

            Console.WriteLine("************************序列化深拷贝*****************************");
            School serSchool = HelperTools.SerializableClone(school);
            serSchool.Name = "序列化";
            serSchool.Number = 1;
            serSchool.Student.Name = "xuliehua";
            serSchool.Student.Age = 20;
            ShowSchoolInfo(serSchool);
            ShowSchoolInfo(school);

            Console.WriteLine("************************新建对象深拷贝****************************");
            School newSchool = (School)school.NewClone();
            newSchool.Name = "new对象";
            newSchool.Number = 2;
            newSchool.Student.Name = "newObject";
            newSchool.Student.Age = 22;
            ShowSchoolInfo(newSchool);
            ShowSchoolInfo(school);

            Console.WriteLine("************************属性反射浅拷贝*****************************");
            School proSchool = HelperTools.PropertyClone(school);
            proSchool.Name = "反射";
            proSchool.Number = 3;
            proSchool.Student.Name = "fanshe";
            proSchool.Student.Age = 21;
            ShowSchoolInfo(proSchool);
            ShowSchoolInfo(school);

            Console.WriteLine("************************克隆接口浅拷贝*****************************");
            School cloneSchool = (School)school.Clone();
            cloneSchool.Name = "克隆";
            cloneSchool.Number = 4;
            cloneSchool.Student.Name = "kelong";
            cloneSchool.Student.Age = 23;
            ShowSchoolInfo(cloneSchool);
            ShowSchoolInfo(school);

            Console.ReadLine();
        }
        public static void ShowSchoolInfo(School school)
        {
            Console.WriteLine("学校名:{0}, 学校编号:{1}, 学生名字:{2}, 学生年龄:{3}", school.Name, school.Number, school.Student.Name, school.Student.Age);
        }
    }

注:实现克隆方法必须继承ICloneable接口,序列化的类必须标明特性[Serializable]

总结:

原型设计模式总算告一段落,从原型设计模式出发,深拷贝、浅拷贝,引用类型、值类型,拷贝方式,再回到起点原始设计模式,这一趟收获颇多。

时间: 2024-08-07 12:26:02

C#设计模式:原型模式(Prototype)及深拷贝、浅拷贝的相关文章

谈谈设计模式~原型模式(Prototype)

返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效:或者创建值相等,只是命名不一样的同类数据. 从原型模式的概念中,我们可以看到,在这个模式里,拷贝是个很重要的概念,即在不创建对象的情况下,返回一个已有对象,这就是拷贝去实现的,在面向对象的编程世界里,拷贝分为浅拷

java语言实现创建型设计模式—原型模式(Prototype)

一.描述 原型模式是通过一个原型对象来标明要创建的对象的类型,然后用复制这个原型对象的方法来拷贝创建更多的同类型对象.例如我们在程序的动态运行过程中有了一个对象,这个对象中包含了一系列的有效数据,我们此时需要一个和该对象完全相同的新对象,并且在拷贝之后,新旧对象之间没有任何联系,对任何一个对象的更改都不影响另一个对象. 在java中所有类都默认继承自java.lang.Object类,在这个Object类中有一个clone()方法,该方法将返回Object对象的一个拷贝. 我们让需要被拷贝的类实

[工作中的设计模式]原型模式prototype

一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.prototype.run=function(){ alert(this.name+" is running"; } 此处的原型是js的特殊定义,在原型上定义的属性和方法所有的类进行共享. 不过设计模式中的原型模式指的是:将已有的对象作为原型,拷贝出一份具有相同属性的新的对象. 模式定义为:原型

设计模式:原型模式(Prototype)

以前听过这样一句话:“程序员的最高境界就是Ctrl+C.Ctrl+V”,我们先不论这句话的对错,就论这个过程,这个过程我们都知道无非就是复制一个对象,然后将其不断地粘贴.这样的过程我们可以将其称之为“克隆”.再如我们应聘的时候打印了那么多的简历. 克隆我们都清楚,就是用一个物体复制若干个一模一样物体.同样,在面向对象系统中,我们同样可以利用克隆技术来克隆出若干个一模一样的对象.在应用程序中,有些对象比较复杂,其创建过程过于复杂,而且我们又需要频繁的利用该对象,如果这个时候我们按照常规思维new该

设计模式(四)原型模式Prototype(创建型)

1.   概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象而不需要提供专门的new()操作就可以快速完成对象的创建,这无疑是一种非常有效的方式,快速的创建一个新的对象. 例子1:孙悟空拔下一嘬猴毛,轻轻一吹就会变出好多的孙悟空来. 例子2:寄个快递下面是一个邮寄快递的场景:“给我寄个快递.”顾客说.“寄往什么地方?寄给……?”你问.“和上次差不多一样,只是邮寄给另外一个地址,这里是邮寄地址……”顾客一边说一边把

二十四种设计模式:原型模式(Prototype Pattern)

原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. 示例有一个Message实体类,现在要克隆它. MessageModel using System; using System.Collections.Generic; using System.Text; namespace Pattern.Prototype { /// <summary> /// Message实体类 /// </summary> publi

深入浅出设计模式——原型模式(Prototype Pattern)

模式动机在面向对象系统中,使用原型模式来复制一个对象自身,从而克隆出多个与原型对象一模一样的对象.在软件系统中,有些对象的创建过程较为复杂,而且有时候需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在. 模式定义原型模式(Prototype Pattern):原型模式是一种对象创建型模式,用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象.原型模式允许一个对象再创建另外一个可定制的对象,无

JAVA 设计模式 原型模式

用途 原型模式 (Prototype) 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式是一种创建型模式. 结构 图-原型模式结构图 Prototype: 声明一个克隆自身的接口.ConcretePrototype: 实现克隆自身的具体操作.Client: 调用 Prototype 来克隆自身,从而创建一个新对象. 应用场景 当要实例化的类是在运行时刻指定时,例如,通过动态装载.为了避免创建一个与产品类层次平行的工厂类层次时.当一个类的实例只能有几个不同状态组合中的一种

Design Patterns 5 原型模式 Prototype

原型模式 Prototype 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. 当我们需要多个相同的类实例时,没必要每次都使用new运算符去创建相同的类实例对象,我们可以用原型模式减少内存的消耗和达到类实例的复用. //带有返回自身接口的抽象原型类 public abstract class Prototype5 { public string Id { get; set; } public Prototype5(string id) { this.Id = id;

10. 星际争霸之php设计模式--原型模式

题记==============================================================================本php设计模式专辑来源于博客(jymoz.com),现在已经访问不了了,这一系列文章是我找了很久才找到完整的,感谢作者jymoz的辛苦付出哦! 本文地址:http://www.cnblogs.com/davidhhuan/p/4248189.html============================================