C#设计模式:原型模式(Prototype)及深拷贝、浅拷贝
原型模式(Prototype)
定义:
原型模式:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。被复制的实例被称为原型,这个原型是可定制的。
Prototype Pattern也是一种创建型模式,它关注的是大量相同或相似对象的创建问题。应用原型模式就是建立一个原型,然后通过对原型来进行复制的方法,来产生一个和原型相同或相似的新对象,或者说用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
模式中的角色
抽象原型类(Abstract Prototype):提供一个克隆接口
具体原型类(Concrete Prototype): 实现了克隆接口的具体原型类
原型模式的优点有:
- 原型模式向客户隐藏了创建新实例的复杂性和具体的产品类,减少了客户知道的名字的数目。
- 原型模式允通过注册原型实例就可以将一个具体产品类并入到系统中,客户可以在运行时刻建立和删除原型。
- 减少了子类的构造。原型模式是Clone一个原型而不是请求工厂方法创建一个,所以它不需要一个与具体产品类平行的Creator类层次。
- 产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构。
- 原型模式具有给一个应用软件动态加载新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响旧系统。
原型模式的缺点有:
原型模式的最重要缺点就是每一个类必须配备一个Clone方法,而且这个Clone方法需要对类的功能进行通盘考虑。这对全新的类来说不是很难,但对已有的类进行改造时,不一定是容易的事。
原型模式可以适用于以下情形:
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等;
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式;
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用;
- 当一个系统应该独立于它的产品创建、构成和表示时;
- 当要实例化的类是在运行时刻指定时,例如通过动态装载来创建一个类;
- 为了避免创建一个与产品类层次平行的工厂类层次时;
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并Clone它们可能比每次用合适的状态手工实例化该类更方便一些。
浅拷贝与深拷贝
浅度复制(Shallow Copy):将原来对象中的所有字段逐个复制到一个新对象,如果字段是值类型,则简单地复制一个副本到新对象,改变新对象的值类型字段不会影响原对象;如果字段是引用类型,则复制的是引用,改变目标对象中引用类型字段的值将会影响原对象。
深度复制(Deep Copy):与浅复制不同之处在于对引用类型的处理,深复制将新对象中引用类型字段指向复制过的新对象,改变新对象中引用的任何对象,不会影响到原来的对象中对应字段的内容。
值类型和引用类型的知识点可以了解:值类型和引用类型深入理解
浅拷贝与深拷贝示例:
拷贝对象School和Student:
[Serializable]
public class Student : ICloneable
{
private string name = "xxx";
private int age = ; 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 = -;
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(, 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]
总结:
原型设计模式总算告一段落,从原型设计模式出发,深拷贝、浅拷贝,引用类型、值类型,拷贝方式,再回到起点原始设计模式,这一趟收获颇多。
备注:
作者:Shengming Zeng
博客:http://www.cnblogs.com/zengming/
本文是原创,欢迎大家转载;但转载时必须注明文章来源,且在文章开头明显处给明链接。
<欢迎有不同想法或见解的同学一起探讨,共同进步>
C#设计模式:原型模式(Prototype)及深拷贝、浅拷贝的更多相关文章
- PHP设计模式 原型模式(Prototype)
定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...
- [工作中的设计模式]原型模式prototype
一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...
- 大话设计模式--原型模式 Prototype -- C++实现
1. 原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象... 注意: 拷贝的时候是浅拷贝 还是 深拷贝, 来考虑是否需要重写拷贝构造函数. 关键在于: virtual Pro ...
- 谈谈设计模式~原型模式(Prototype)
返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式 ...
- 设计模式——原型模式(Prototype)
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.——DP UML类图 模式说明 如果把在一张纸上手写一篇简历的过程看成是类的实例化过程,那么通过原型模式创建对象的过程就是拿着这张纸到复印 ...
- 设计模式--原型模式Prototype(创建型)
一.原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.原型模式实现的关键就是实现Clone函数,还需要实现深拷贝. 二.UML类图 三.例子 //父类 class Resume ...
- C#设计模式——原型模式(Prototype Pattern)
一.概述 在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定.对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依 ...
- 设计模式-原型模式(Prototype)
场景分析: 前面我们提到,交易对象Trade,还有继承他的债券交易BondTrade.期货交易FutureTrade. 现在有一个需求,需要提供方法将交易拆分成多笔小交易. 代码如下(如果没有clon ...
- 设计模式——原型模式(Prototype Pattern)
原型模式:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象. UML 图: 原型类: package com.cnblog.clarck; /** * 原型类 * * @author c ...
- PHP 设计模式 原型模式(Prototype)之深/浅拷贝
看PHP 设计模式 原型模式(Prototype)时,衍生出一个扩展问题之 原型拷贝的浅拷贝和深拷贝问题(不管写Java还是写PHP还是写JS时都多多少少遇到过对象拷贝问题) 比如写前端页面时 ...
随机推荐
- 【腾讯Bugly干货分享】Android Patch 方案与持续交付
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57a31921ac3a1fb613dd40f3 Android 不仅系统版本众多 ...
- Alcatraz 的安装和删除
Xcode 所有的插件都安装在目录: ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/ 你也可以手工切换到这个目录来删除插件 ...
- 微信小程序开发工具测评
1月9日微信小程序正式上线.很多企业都希望能在这个.但是在技术开发的问题上,却不知道该如何下手.经过一些程序员不辞辛苦连夜测试,终于从十余款工具呕心沥血筛选出四款比较靠谱实用的微信小程序开发工具.接下 ...
- Atitit 输入法原理与概论ati use
Atitit 输入法原理与概论ati use 1.1. 输入法技术点1 1.2. 参考多多输入法设置2 1.3. Attilax博客集合知识点2 1.4. 输入法的书籍当当几乎没有..都是打字的.2 ...
- openresty 前端开发入门六之调试篇
大多数情况下,调试信息,都可以通过ngx.say打印出来,但是有的时候,我们希望打印调试日志,不影响到返回数据,所以系统打印到其它地方,比如日志文件,或者控制台 这里主要用到一个方法就是ngx.log ...
- SQL Server 进制转换函数
一.背景 前段时间群里的朋友问了一个问题:“在查询时增加一个递增序列,如:0x00000001,即每一个都是36进位(0—9,A--Z),0x0000000Z后面将是0x00000010,生成一个像下 ...
- 坎坷路:ASP.NET 5 Identity 身份验证(上集)
之所以为上集,是因为我并没有解决这个问题,写这篇博文的目的是纪录一下我所遇到的问题,以免自己忘记,其实已经忘了差不多了,写的过程也是自己回顾的过程,并且之前收集有关 ASP.NET 5 身份验证的书签 ...
- 网站文件系统发展&&分布式文件系统fastDFS
网站文件系统发展 1.单机时代的图片服务器架构 初创时期由于时间紧迫,开发人员水平也很有限等原因.所以通常就直接在website文件所在的目录下,建立1个upload子目录,用于保存用户上传的图片文件 ...
- JS将秒转换为 天-时-分-秒
记录一下,备忘.. function SecondToDate(msd) { var time =msd if (null != time && "" != tim ...
- LinqToDB 源码分析——轻谈Linq查询
LinqToDB框架最大的优势应该是实现了对Linq的支持.如果少了这一个功能相信他在使用上的快感会少了一个层次.本来笔者想要直接讲解LinqToDB框架是如何实现对Linq的支持.写到一半的时候却发 ...