创建型设计模式
Posted Huangxiaomao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型设计模式相关的知识,希望对你有一定的参考价值。
原型模式
概念
原型模式是23种设计模式之一。用于创建重复的对象。
浅拷贝与深拷贝
浅拷贝: 自带的MemberwiseClone方法,这种方法实现的浅拷贝,如果对象中包含有引用类型,拷贝的是栈中的地址,指向的都是同一个堆地址。
深拷贝: 值类型和引用类型完全拷贝。有两种方法可以实现,第一个是利用序列化和反序列化;第二是利用反射加上递归。
核心代码
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;
}
以上是关于创建型设计模式的主要内容,如果未能解决你的问题,请参考以下文章