原型模式(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 = ; 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)及深拷贝、浅拷贝的更多相关文章

  1. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

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

    一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...

  3. 大话设计模式--原型模式 Prototype -- C++实现

    1. 原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象... 注意: 拷贝的时候是浅拷贝 还是 深拷贝, 来考虑是否需要重写拷贝构造函数. 关键在于: virtual Pro ...

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

    返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式 ...

  5. 设计模式——原型模式(Prototype)

    用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.——DP UML类图 模式说明 如果把在一张纸上手写一篇简历的过程看成是类的实例化过程,那么通过原型模式创建对象的过程就是拿着这张纸到复印 ...

  6. 设计模式--原型模式Prototype(创建型)

    一.原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.原型模式实现的关键就是实现Clone函数,还需要实现深拷贝. 二.UML类图 三.例子 //父类 class Resume ...

  7. C#设计模式——原型模式(Prototype Pattern)

    一.概述 在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定.对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依 ...

  8. 设计模式-原型模式(Prototype)

    场景分析: 前面我们提到,交易对象Trade,还有继承他的债券交易BondTrade.期货交易FutureTrade. 现在有一个需求,需要提供方法将交易拆分成多笔小交易. 代码如下(如果没有clon ...

  9. 设计模式——原型模式(Prototype Pattern)

    原型模式:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象. UML 图: 原型类: package com.cnblog.clarck; /** * 原型类 * * @author c ...

  10. PHP 设计模式 原型模式(Prototype)之深/浅拷贝

      看PHP 设计模式 原型模式(Prototype)时,衍生出一个扩展问题之 原型拷贝的浅拷贝和深拷贝问题(不管写Java还是写PHP还是写JS时都多多少少遇到过对象拷贝问题)   比如写前端页面时 ...

随机推荐

  1. 清除Android工程中没用到的资源

    项目需求一改再改,UI一调再调,结果就是项目中一堆已经用不到但却没有清理的垃圾资源,不说工程大小问题,对新进入项目的人或看其他模块的代码的人来说,这些没清理的资源可能也可能会带来困扰,所以最好还是清理 ...

  2. java运行时获得泛型类型

    引言 众所周知,java泛型最重要的特征是泛型擦除,所有泛型在编译时会转换成Object所以在java中运行时无法获得泛型的类型. 但是其实以上的规则是针对方法的内部变量的,如果是其他形式的泛型其实是 ...

  3. FASTDFS调研报告(V1.0)

    之前的文章,现在放出来,以供参阅. 一.fastdfs简介 FastDFS是一个轻量级的开源分布式文件系统 FastDFS主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡 Fas ...

  4. Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结

    Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结 1. 验证码的前世今生11.1. 第一代验证码 图片验证码11.2. 第二代验证码  用户操作 ,比如 ...

  5. 设计C/S架构应用程序的并发功能

    C/S架构的ERP.CRM程序有的是以并发点(Concurrency)来销售,并发点是指同时在线人数.并发数量大时,理论上程序的运行速度会慢,软件供应商(vendor)也以控制并发的上限以解决客户对系 ...

  6. 【译】Unity3D Shader 新手教程(2/6) —— 积雪Shader

    本文为翻译,附上原文链接. 转载请注明出处--polobymulberry-博客园. 如果你是一个shader编程的新手,并且你想学到下面这些酷炫的技术,我觉得你可以看看这篇教程: 实现一个积雪效果的 ...

  7. Notes:SVG(3)---滤镜和渐变

    SVG滤镜使用filter标签来定义,该标签必须嵌套在defs元素里面,并且必须指定一个ID,以供引用. 在 SVG 中,可用的滤镜有: feBlend feColorMatrix feCompone ...

  8. OCP考点实战演练02-日常维护篇

    本系列宗旨:真正掌握OCP考试中所考察的技能,坚决不做Paper OCP! 实验环境:RHEL 6.4 + Oracle 11.2.0.4 OCP考点实战演练02-日常维护篇 1.数据库体系结构和AS ...

  9. 读书笔记--SQL必知必会19--存储过程

    不同的DBMS对存储过程的实现不同,差异巨大,这里不涉及具体的DBMS,仅仅说明存储过程的简单含义. 19.1 存储过程 简单来说,存储过程就是为以后使用而保存的一条或多条SQL语句. 可以将存储过程 ...

  10. SSRS 实用技巧 ---- 为表格添加展开/折叠操作(明细报表)

    相信很多人都会遇到这样的需求:当表格按照某几个列分组时,需要为组添加展开和折叠的操作. 最初展现表格的时候只展现最外层分组,然后点击展开后可以查看分组内的明细情况. 先来一张效果图,然后再看具体如何实 ...