基础介绍:

  具体可分为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. 《Among Us》火爆全球,实时语音助力派对游戏开启第二春

    今年在全球"宅经济"的影响下,社交派对类游戏意外的迎来了爆发. 8月份,<糖豆人:终极淘汰赛>突然爆火,创造了首日150万玩家.首周Steam 200万销量.单周Twi ...

  2. 1.简述Hibernate的工作原理。

    (1).首先,Configuration读取Hibernate的配置文件和映射文件中的信息,即加载配置文件和映射文件,并通过Hibernate配置文件生成一个多线程的SessionFactory对象: ...

  3. 学习 YAML 语法

    符号 意义 备注 - 表示数组 数组也叫序列 # 表示注释 只支持单行注释 空格缩进 表示层级关系 相同层级左侧必须对齐 --- 表示一份内容的开始 ... 表示一份内容的结束 可省略 : 表示键值对 ...

  4. 超越.NET极限:我打造的高精度数值计算库

    超越.NET极限:我打造的高精度数值计算库 还记得那一天,我大学刚毕业,紧张又兴奋地走进人生第一场.NET工作面试.我还清楚地记得那个房间的气氛,空调呼呼地吹着,面试官的表情严肃而深沉.我们进行了一番 ...

  5. IIC总线学习笔记

    IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板.嵌入式系统或手 ...

  6. bzip2: (stdin) is not a bzip2 file.

    用tar -zxvf dir.tar.gz命令解压即可.

  7. [docker]封装python的docker镜像

    前言 基于alpine的python镜像封装. docker pull python:3.10-alpine 准备 requirements.txt内容: fastapi uvicorn server ...

  8. [db2]数据库管理

    前言 db2版本:10.5 实例所有者:db2inst1 待新建数据库:ticm,授权用户:ticm/123456.(用户是系统用户) 创建数据库 建库 # create database ticm: ...

  9. LabVIEW图形化的AI视觉开发平台(非NI Vision)VI简介

    前言 今天想和大家分享的是:仪酷LabVIEW AI视觉工具包的VI简介,如介绍内容有误,欢迎各位朋友们帮忙纠正~ 一.AI视觉工具包VI简介 已经安装好的AI工具包位于程序框图-函数选板-Addon ...

  10. 推荐一款免费好用的远程桌面:Getscreen

    因为平时有多台设备要用,所以远程桌面是我经常要使用的工具. 最近,正好看到一款不错的远程桌面软件,马上拿出来推荐给大家,如果有需要的可以看看. 今天要推荐的远程桌面软件就是这款叫Getscreen的软 ...