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时都多多少少遇到过对象拷贝问题) 比如写前端页面时 ...
随机推荐
- 用Go语言做产品半年的一些感觉
用Go语言做产品刚好半年,有一些感觉跟大家说道说道. 在使用Go之前,我常常想象,无法使用先进的Debug工具会对工作进度造成多么巨大的影响.甚至在Visual Studio的娇惯下认为,不能调试基本 ...
- 警告: [unchecked] 对作为原始类型IScheme的成员的write(TProt ocol,T)的调用未经过检查
jdk 从8 改成了7 就好了! 或者, 修改源码, 每个响应的地方加上 surppressingWarnings xxx , 或者使用 请使用 -Xlint:unchecked 重新编译. 参照 h ...
- Android colors资源文件常用的颜色
<?xml version="1.0" encoding="utf-8"?> <resources> <color name=&q ...
- 【Win 10 应用开发】透视效果
所谓透视效果,就是在平面坐标空间上模拟出“好像”三维的效果.要是老周没有记错的话,以前在写WP8相关的内容时写过,UWP中的透视方法也保留了以前的Do法,其实这玩意儿是从 Silverlight 沿袭 ...
- Java资源大全中文版(Awesome最新版)
Awesome系列的Java资源整理.awesome-java 就是akullpp发起维护的Java资源列表,内容包括:构建工具.数据库.框架.模板.安全.代码分析.日志.第三方库.书籍.Java 站 ...
- 2、C#核心编程结构
本学习主要参考Andrew Troelsen的C#与.NET4高级程序设计,这小节主要述说以下几个东西: Hello World的Main方法: 利用VS2010新建一个控制台应用程序Hello W ...
- web前端性能调优
最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...
- Oracle简单常用的数据泵导出导入(expdp/impdp)命令举例(上)
<Oracle简单常用的数据泵导出导入(expdp/impdp)命令举例(上)> <Oracle简单常用的数据泵导出导入(expdp/impdp)命令举例(下)> 目的:指导项 ...
- 探寻 JavaScript 逻辑运算符(与、或)的真谛
十二月已经过半,冬季是一个美妙的季节,寒冷的空气逼得人们不得不躲在安逸舒适的环境里生活.冬季会给人一种安静祥和的氛围,让人沉浸在其中,仿佛是一个旧的阶段的结束,同时也是一个新的阶段的开始.这么说来,西 ...
- c#+handle.exe实现升级程序在运行时自动解除文件被占用的问题
我公司最近升级程序经常报出更新失败问题,究其原因,原来是更新时,他们可能又打开了正在被更新的文件,导致更新文件时,文件被其它进程占用,无法正常更新而报错,为了解决这个问题,我花了一周时间查询多方资料及 ...