基础介绍:

  具体可分为2个角色:

    Prototype(原型类):声明一个Clone自身的接口;

    ConcretePrototype(具体原型类):,实现一个Clone自身的操作。

  在原型模式中,Prototype通常提供一个包含Clone方法的接口,具体的原型ConcretePrototype使用Clone方法完成对象的创建。

  本质:通过拷贝这些原型对象创建新的对象。

  根据其本质可以理解,原型本身就是通过一个自身的Clone方法来进行自我复制,从而产生新的对象。

  比如,孙猴子吹猴毛变化多个克隆体时,就是用了原型模式,通过对自身的自我复制从而生产出N个分身。

  所以从本质出发,想要实现这个功能,可以引出两个概念:其一就是浅层复制,再则就是深层复制

  浅层复制:通过this.MemberWiseClone(),对实例的值类型进行拷贝(包含string类型),对引用类型只拷贝了引用。浅拷贝只对值类型成员进行复制,对于引用类型,只是复制了其引用,并不复制其对象。

  深层复制需要通过反射和序列化来实现。

应用场景:

  对象在创建(new)时,消耗资源过多繁琐耗时。

  本质就是在对象的构造函数中有耗时长或者占用系统资源多的情况,

  使用原型模式进行复制对象时,可以省去这些耗时耗力的操作,直接获得对象的具体实例。

  最常见的使用场景之一就是对象历史节点的保存,比如在对对象进行操作一次后,进行一次复制保存当前状态(恢复到某一历史状态),可实现撤销操作。

创建方式:

  1. 原型类----用来规范具体原型

     1     /// <summary>
    2 /// 原型类
    3 /// </summary>
    4 public abstract class Prototype
    5 {
    6 /// <summary>
    7 /// 值类型
    8 /// </summary>
    9 public int Id { get; set; }
    10
    11 /// <summary>
    12 /// 字符串
    13 /// </summary>
    14 public string strMessage { get; set; }
    15
    16 /// <summary>
    17 /// 引用类型
    18 /// </summary>
    19 public Dictionary<int, string> keyValuePairs = new Dictionary<int, string>() { };
    20
    21 /// <summary>
    22 /// 构造函数
    23 /// </summary>
    24 /// <param name="id"></param>
    25 public Prototype(int id)
    26 {
    27 this.Id = id;
    28 }
    29
    30 /// <summary>
    31 /// 复制函数
    32 /// </summary>
    33 /// <returns></returns>
    34 public abstract Prototype Clone();
    35 }

    通过上述代码可以看出,为了更好的展示原型类的特性,原型类中声明了值类型和引用类型来展示各自的变化。

  2. 具体原型类

     1     /// <summary>
    2 /// 创建具体原型
    3 /// </summary>
    4 public class ConcretePrototype : Prototype
    5 {
    6 public ConcretePrototype(int id)
    7 : base(id)
    8 { }
    9
    10 /// <summary>
    11 /// 浅拷贝
    12 /// </summary>
    13 /// <returns></returns>
    14 public override Prototype Clone()
    15 {
    16 // 调用MemberwiseClone方法实现的是浅拷贝,另外还有深拷贝
    17 return (Prototype)this.MemberwiseClone();
    18 }
    19 }

    通过MemberwiseClone方法实现浅拷贝,即复制值类型属性生成新的,而引用类型的属性只复制其引用,并没有生成新的。

  3. 客户端调用

     1     class Program
    2 {
    3 static void Main(string[] args)
    4 {
    5 ConcretePrototype concretePrototype = new ConcretePrototype(1);
    6 concretePrototype.strMessage = "AAAAAAAAA";
    7 concretePrototype.keyValuePairs.Add(1, "A");
    8 concretePrototype.keyValuePairs.Add(2, "B");
    9 Console.WriteLine("id:{0}", concretePrototype.Id);
    10 Console.WriteLine("strMessage:{0}", concretePrototype.strMessage);
    11 Console.WriteLine("keyValuePairs:");
    12 foreach (KeyValuePair<int,string> item in concretePrototype.keyValuePairs)
    13 {
    14 Console.WriteLine("KEY:{0} Value:{1}", item.Key, item.Value);
    15 }
    16
    17 Console.WriteLine("\r\n");
    18
    19 ConcretePrototype concretePrototype2 = (ConcretePrototype)concretePrototype.Clone();
    20 concretePrototype2.strMessage = "BBBBBBBBB";
    21 concretePrototype2.keyValuePairs[1] = "A1";
    22 Console.WriteLine("id:{0}", concretePrototype2.Id);
    23 Console.WriteLine("strMessage:{0}", concretePrototype2.strMessage);
    24 Console.WriteLine("keyValuePairs:");
    25 foreach (KeyValuePair<int, string> item in concretePrototype2.keyValuePairs)
    26 {
    27 Console.WriteLine("KEY:{0} Value:{1}", item.Key, item.Value);
    28 }
    29
    30 Console.WriteLine("\r\n");
    31
    32 Console.WriteLine("id:{0}", concretePrototype.Id);
    33 Console.WriteLine("strMessage:{0}", concretePrototype.strMessage);
    34 Console.WriteLine("keyValuePairs:");
    35 foreach (KeyValuePair<int, string> item in concretePrototype.keyValuePairs)
    36 {
    37 Console.WriteLine("KEY:{0} Value:{1}", item.Key, item.Value);
    38 }
    39 Console.ReadKey();
    40 }
    41 }

    上述代码中,首先创建了一个concretePrototype原型对象,然后给字符串类型的strMessage赋值“AAAAAAAAA”。 然后给引用类型的keyValuePairs字典添加key=1和key=2,值分别是A和B。

    通过Clone()方法进行原型对象的复制操作,生成新对象concretePrototype2。

    修改新对象中的strMessage属性和keyValuePairs字典中key=1的值为“A1”。

    通过打印出的内容可以看出新对象中的strMessage值修改并不会影响原型对象中的内容,而引用类型keyValuePairs则发生了改变。

    通过这个实例可以看出浅复制,对值类型进行全盘拷贝,对引用类型只拷贝了引用地址。

  4. 修改上述实例,将浅复制改为深复制

     1     /// <summary>
    2 /// 原型类
    3 /// </summary>
    4 [Serializable]
    5 public abstract class Prototype
    6 {
    7 ......
    8 }
    9
    10 /// <summary>
    11 /// 创建具体原型
    12 /// 如果是要通过序列化来进行深拷贝的话,要打上Serializable标签
    13 /// </summary>
    14 [Serializable]
    15 public class ConcretePrototype : Prototype
    16 {
    17 public ConcretePrototype(int id)
    18 : base(id)
    19 { }
    20
    21 /// <summary>
    22 /// 深拷贝
    23 /// </summary>
    24 /// <returns>返回一个全新的Person对象</returns>
    25 public override Prototype Clone()
    26 {
    27 //创建一个内存流
    28 MemoryStream ms = new MemoryStream();
    29 //创建一个二进制序列化对象
    30 BinaryFormatter bf = new BinaryFormatter();
    31 //将当前对象序列化写入ms内存流中
    32 bf.Serialize(ms, this);
    33 //设置流读取的位置
    34 ms.Position = 0;
    35 //将流反序列化为Object对象
    36 return bf.Deserialize(ms) as Prototype;
    37 }
    38 }

    上述实例通过序列化进行深复制,当然也可以使用反射等技术进行深复制。

    运行后可以看出,深复制后引用类型也会生成一个新的地址。

总结:

  原型模式就是对对象进行复制操作,而避免重复进行初始化操作,生产多个克隆对象。

  

  

c#中原型模式详解的更多相关文章

  1. (二十三)原型模式详解(clone方法源码的简单剖析)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...

  2. 设计模式之 原型模式详解(clone方法源码的简单剖析)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...

  3. 二十三:原型模式详解(clone复制方法源码)

    定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.                 定义比较简单,总结一下是通过实例指定种类,通过拷贝创建对象. 在JAVA语言中使用原型模式是非常 ...

  4. JAVA 设计模式之 原型模式详解

    原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式利用的是克隆的原理,创建新的对象,JDK提供的Cloneable 和JSON. ...

  5. 深入浅出的webpack构建工具---devTool中SourceMap模式详解(四)

    阅读目录 一:什么是SourceMap? 二:理解webpack中的SourceMap的eval,inline,sourceMap,cheap,module 三:开发环境和线上环境如何选择source ...

  6. Javascript设计模式之装饰者模式详解篇

    一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改 ...

  7. 你不知道的JavaScript--Item15 prototype原型和原型链详解

    用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性,可以为其添加函数供实例访问,其它的就不清楚了, ...

  8. Javascript中prototype属性详解 (存)

    Javascript中prototype属性详解   在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不 ...

  9. 从mixin到new和prototype:Javascript原型机制详解

    从mixin到new和prototype:Javascript原型机制详解   这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...

  10. 【转载】C/C++中extern关键字详解

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

随机推荐

  1. 【后端面经-Java】JVM垃圾回收机制

    目录 1. Where:回收哪里的东西?--JVM内存分配 2. Which:内存对象中谁会被回收?--GC分代思想 2.1 年轻代/老年代/永久代 2.2 内存细分 3. When:什么时候回收垃圾 ...

  2. javascript中一些难以理解的专有名词 2(也不是很专有)

    作用域链 让人迷惑的例子 function foo() {console.log(v)} function foo1() { var v = "v1" foo() console. ...

  3. 查看Nginx是否启动

    查看Nginx进程 ps -ef | grep nginx 输出如下: root 1036 1 0 Jul15 ? 00:00:00 nginx: master process /www/server ...

  4. 小白也能搞定!Windows10上CUDA9.0+CUDNN7.0.5的完美安装教程

    前言: 为什么要在本地电脑安装 CUDA,CUDA 是什么的,用来做什么?我想,点击标题进来的小伙伴,应该都清楚这些.不管你是用来做什么,或者跟我一样为了跑 Tensorflow 的 Object D ...

  5. python-多继承构造函数声明问题

    背景 有场景分别定义两组逻辑,随后有统一入口做基类属性的整合 其中两组逻辑的积累构造函数定义入参不同 设计类继承图如: 实际的使用方式抽象为[使用] 小节 实际开发过程中遇到问题 先说结论 pytho ...

  6. Mybatis-plus SQL效率插件PerformanceInterceptor无效->替换为p6spy

    使用mybatis-plus时,需要加入执行的sql分析 发现mybatis-plus中的PerformanceInterceptor无效了 查了信息发现 3.2.0 版本之后把这个功能可剔除了 可同 ...

  7. idea 热部署插件 JRebel 安装

    idea 热部署插件 JRebel 安装 1.安装 直接在idea 插件搜索安装 JRebel and XRebel 安装,安装后需要破解才能使用 2.破解 破解原来需要远程连接服务器破解或者下载源码 ...

  8. 《SQL与数据库基础》11. 索引

    目录 索引 概述 结构 B-Tree B+Tree Hash 思考 分类 语法 SQL性能分析 SQL执行频率 慢查询日志 profile详情 explain执行计划 索引失效情况 范围查询 索引列运 ...

  9. ssm框架的事物控制

    事物控制统一在逻辑层的实现类中以注解的形式添加,例如:对UserServiceImpl中的addUser方法需要进行事物控制,操作如下: 1.此方法必须为public2.在方法名上边加入@Transa ...

  10. Spring Boot中自动装配机制的原理

    SpringBoot中自动装配机制的原理 1.自动装配,简单来说就是自动把第三方组件的Bean装载到Spring IOC容器里面,不需要开发人员再去写Bean的装配配置, 2.在Spring Boot ...