创建型设计模式

Posted Huangxiaomao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型设计模式相关的知识,希望对你有一定的参考价值。

原型模式

概念

原型模式是23种设计模式之一。用于创建重复的对象。

浅拷贝与深拷贝

浅拷贝: 自带的MemberwiseClone方法,这种方法实现的浅拷贝,如果对象中包含有引用类型,拷贝的是栈中的地址,指向的都是同一个堆地址。
深拷贝: 值类型和引用类型完全拷贝。有两种方法可以实现,第一个是利用序列化和反序列化;第二是利用反射加上递归。

核心代码

23种设计模式github代码

  
 using System;
using System.Collections.Generic;
using System.Text;

namespace CreateTypeDesignPatterns
{

    public class Prototype
    {

        public static void Show()
        {
              PrototypeProduct product = new PrototypeProduct
            {
                Name = "product1",
                Num = 1,
                type = new Type() { TypeId = 1 }
            };
            var product2 = product.ShallowClone();
            product2.Num = 2;
            product2.Name = "product2";
            product2.type.TypeId = 2;
          
            //值类型完全拷贝
            Console.WriteLine(product.Num);//1
            Console.WriteLine(product2.Num);//2

            //不是说引用类型只拷贝地址吗?为什么修改了produtct2的Name值,Product1的值还是原来的呢?
            //引用类型拷贝地址是对的,但是字符串类型有的特殊,因为字符串类型是不可变的。修改product2的Name值相当于新创建了一个string类型的值
            Console.WriteLine(product.Name);//product1
            Console.WriteLine(product2.Name);//product2

            //引用类型的浅拷贝,这里就体现出来了
            //修改了product2的type,product1中的type也随着改变
            Console.WriteLine(product.type.TypeId); //2
            Console.WriteLine(product2.type.TypeId); //2  

            
            product2.type = new Type() { TypeId = 3 };
            //这里修改了product2中的type值,为什么product中的type没有发生改变呢?
            //因为product2重新创建了一个type,和product中的type指向的不是同一个堆内存空间了
            //上面所提到的字符串可以参考这一条
            Console.WriteLine(product.type.TypeId); //2
            Console.WriteLine(product2.type.TypeId); //3

        }
    }

    public class PrototypeProduct
    {
        
        public int Num { get; set; }
        public string Name { get; set; }

        public Type type { get; set; }

        //浅拷贝
        public PrototypeProduct ShallowClone()
        {
            return (PrototypeProduct)this.MemberwiseClone();
        }
    }

    public class Type 
    {
        public int TypeId { get; set; }
    }
}

深拷贝实现的两种方式

序列化 + 内存流
要保证相关对象有[Serializable]特性

     /// <summary>
        /// 通过序列化+二进制  实现深拷贝
        /// 原对象相关的类必须添加Serializable
        /// </summary>
        public static object DeepCloneBySerialize(this object obj)
        {
            if (obj == null || obj is string || obj.GetType().IsValueType)
            {
                return obj;
            }
            using (MemoryStream ms = new MemoryStream())
            {
                //二进制序列化器
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                //将对象写入内存流
                binaryFormatter.Serialize(ms, obj);
                //将当前流中的位置设置为指定值
                ms.Seek(0, SeekOrigin.Begin);
                //反序列化成对象
                object result = binaryFormatter.Deserialize(ms);
                return result;
            }
        }

反射 + 递归

/// <summary>
        /// 通过反射 + 递归   实现深拷贝
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static object DeepCloneByReflect(this object obj)
        {
            //如果是值类型或者是字符串类型返回原值
            //递归出口
            if (obj == null || obj is string || obj.GetType().IsValueType)
            {
                return obj;
            }

            var type = obj.GetType();
            //根据对象的type类型,创建一个新的空对象
            //构造函数模式是公开的
            object result = Activator.CreateInstance(type);
            //根据type值可以获取类中所有的属性和字段
            FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            foreach (FieldInfo field in fieldInfos)
            {
                //这里用到了递归
                //将原对象的属性值一一赋值到新对象中,因为原对象的属性值有可能是多层引用值,所以要用到递归
                //递归的出口就是这个属性的值是值类型或者是字符串类型
                field.SetValue(result,field.GetValue(obj).DeepCloneByReflect());
            }
            return result;
        }

以上是关于创建型设计模式的主要内容,如果未能解决你的问题,请参考以下文章

创建型模式 工厂模式

设计模式 - 创建型模式_原型模式

设计模式 - 创建型模式_原型模式

设计模式 - 创建型模式_原型模式

设计模式 - 创建型模式_工厂方法模式

设计模式 - 创建型模式_工厂方法模式