原型模式就是用于创建重复的对象,当想要创建一个新的对象但是开销比较大或者想将对象的当前状态保存下来的时候,我们就可以使用原型模式。

创建原型

public abstract class Base
{
//因为String的特殊性,所以此次演示我们使用StringBuilder
public StringBuilder Name { get; set; }
public int Age { get; set; } public Base()
{
//模拟创建对象花费的开销
Thread.Sleep();
} public Base(String name, int age)
{
this.Name = new StringBuilder(name);
this.Age = age;
//模拟创建对象花费的开销
Thread.Sleep();
} //深拷贝
public abstract Base Clone();
//浅拷贝
public abstract Base MClone();
}

接下来创建一个Peron类,继承Base,并且实现两个复制方法

//如果是要通过序列化来进行深拷贝的话,要打上Serializable标签
[Serializable]
public class Person : Base
{
public Person()
: base()
{ }
public Person(String name, int age)
: base(name, age)
{ }
/// <summary>
/// 深拷贝
/// </summary>
/// <returns>返回一个全新的Person对象</returns>
public override Base Clone()
{
//创建一个内存流
MemoryStream ms = new MemoryStream();
//创建一个二进制序列化对象
BinaryFormatter bf = new BinaryFormatter();
//将当前对象序列化写入ms内存流中
bf.Serialize(ms, this);
//设置流读取的位置
ms.Position = ;
//将流反序列化为Object对象
return bf.Deserialize(ms) as Person;
} /// <summary>
/// 浅拷贝
/// </summary>
/// <returns></returns>
public override Base MClone() =>
//浅拷贝
this.MemberwiseClone() as Person;
}

Main方法中调用,首先我们每次都创建新的Person对象

static void Main(string[] args)
{
//用于计时
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start(); Person p = new Person("a",2);
Person p2 = new Person("a",);
Person p3 = new Person("a",2); stopwatch.Stop();
Console.WriteLine("耗时:"+stopwatch.Elapsed);
Console.ReadKey();
}

运行结果:

可见如果创建对象如果开销很大的话,每次用的时候都创建效率就会很低

接下来我们使用原型模式来创建重复的对象,调用MClone()浅拷贝

static void Main(string[] args)
{
//用于计时
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start(); Person p = new Person("a",);
Person p1 = p.MClone() as Person;
Person p2 = p.MClone() as Person; //记录下来name的值,后续通过即时窗口查看
StringBuilder name2 = p2.Name;
StringBuilder name1 = p1.Name; stopwatch.Stop();
Console.WriteLine("耗时:"+stopwatch.Elapsed);
Console.ReadKey();
}

在Console.ReadKey();处设置断点,运行程序,打开  调试>>窗口>>即时,在右下角即时窗口输入  *&name1  回车,*&name2   回车,查看name1和name2的内存地址

我们可以看到,name1和name2的内存地址都是相同的,说明p2.Name和p1.Name是指向了同一个引用。所以对于属性是引用类型的对象,实现浅拷贝,所有的属性引用只会指向同一个对象,也就是说只要有一个对象修改了Name属性,其他的对象的Name属性都会发生改变。

看一下运行结果

可以发现,只有第一次创建对象需要很大的开销,通过原型复制的话是很快的。

接下来我们看一下深拷贝

static void Main(string[] args)
{
//用于计时
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start(); Person p = new Person("a",);
Person p1 = p.Clone() as Person;
Person p2 = p.Clone() as Person; //记录下来name的值,后续通过即时窗口查看
StringBuilder name2 = p2.Name;
StringBuilder name1 = p1.Name; stopwatch.Stop();
Console.WriteLine("耗时:"+stopwatch.Elapsed);
Console.ReadKey();
}

执行和刚才相同的操作,来看一下内存地址

可以发现,p1和p2的Name在内存中的地址是不一样的, 就是说明深拷贝会将对象的所有非静态属性都复制一份,如果碰到引用类型也会重新创建一份,而不是复制指向对象的引用。

最后我们看一下运行结果

C#原型模式(深拷贝、浅拷贝)的更多相关文章

  1. Prototype 原型模式 复制 浅拷贝 clone MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. Java原型模式之浅拷贝-深拷贝

    一.是什么? 浅拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量仅仅复制引用,不复制引用的对象 深拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制 内部机制: ...

  3. 设计模式:原型模式介绍 && 原型模式的深拷贝问题

    0.背景 克隆羊问题:有一个羊,是一个类,有对应的属性,要求创建完全一样的10只羊出来. 那么实现起来很简单,我们先写出羊的类: public class Sheep { private String ...

  4. Java原型模式之基础

    一.是什么? 定义:用原型实例指定创建对象的种类,而且通过拷贝这些原型创建新的对象.(官方定义) 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype. Prototype类须要 ...

  5. 设计模式学习-使用go实现原型模式

    原型模式 定义 代码实现 优点 缺点 适用场景 参考 原型模式 定义 如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复 ...

  6. C#设计模式:原型模式(Prototype)及深拷贝、浅拷贝

    原型模式(Prototype) 定义: 原型模式:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象.被复制的实例被称为原型,这个原型是可定制的. Prototype Pattern也是一 ...

  7. 设计模式_11_原型模式(prototype)深拷贝、浅拷贝

    设计模式_11_原型模式(prototype) 浅拷贝: package designPatternOf23; /** * 定义:用原型实例,指定创建对象的种类,并通过拷贝这些原型创建新的对象 * P ...

  8. 设计模式之原型模式(深入理解OC中的NSCopying协议以及浅拷贝、深拷贝)

    原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.原型模式其实就是从一个对象再创建另一个可定制的对象,而且不需知道任何创建的细节. 比如说,有一个Person类,有firstN ...

  9. Java clone克隆方法 --深拷贝--浅拷贝 --原型模型

    什么是深拷贝? 什么是浅拷贝? 创建一个对象的方法有几种? 默认的Object方法中的clone是深拷贝还是浅拷贝? 为什么说很多深拷贝都是不彻底的深拷贝? 什么是原型模型,什么是原型模式? 原型模型 ...

随机推荐

  1. Redis set集合

    Set操作.Set集合就是不允许重复的列表 (无序集合) sadd(name,values) # name对应的集合中添加元素 scard(name) # 获取name对应的集合中元素个数 sdiff ...

  2. 【07】Nginx:状态统计 / 状态码统计

    写在前面的话 在 nginx 中,有些时候我们希望能够知道目前到底有多少个客户端连接到了我们的网站.我们希望有这样一个页面来专门统计显示这些情况.这个需求在 nginx 中是可以实现的,我们可以通过简 ...

  3. 使用 Xbox Game 录制桌面视频(录制音频)

    使用 Xbox Game 录制桌面视频(附带音频) 前言:可能自己音频输出的问题,一直无法用工具录制桌面的音频,而最后发现利用 Xbox Game 录制游戏视频的功能很好地解决我们的问题. 1)打开游 ...

  4. Xamarin移动开发备忘

    vs2017下: 1.debug用于本地生成和调试,release用于发布.区别主要在于: 安卓项目的生成选项属性中,开发者模式release是不勾的,而且高级里的cpu不同(debug是x86,re ...

  5. Python基础18

    “为什么有列表,还要元组?” 1. 元组可看成是简单的对象组合,而列表是随时间改变的数据集合. 2. 元组的不可变特性提供了某种完整性,确保元组不会被另一个引用来修改.类似于其它语言中的常数声明.

  6. Java基础—实现多线程的三种方法

    Java虚拟机(JVM,是运行所有Java程序的抽象计算机,是Java语言的运行环境)允许应用程序并发地运行多个线程.在Java语言中,多线程的实现一般有以下三种方法: 1.实现Runnable接口, ...

  7. iOS开发 简单实现视频音频的边下边播 (转)

      1.ios视频音频边缓存边播放,缓存时可以在已下载的部分拖拽进度条. 3.无论是下载到一半退出还是下载完退出,已缓存的数据都存到自己指定的一个路径.如果已下载完,下次播放时可以不再走网络,直接播放 ...

  8. CATransform3D 特效详解

    http://blog.sina.com.cn/s/blog_8f5097be0101b91z.html

  9. APP弱网测试方法

    常用工具 •利用抓包工具   -Fiddler/Charles•使用chrome浏览器的开发者工具•使用手机自带的限速功能(只适用IOS设备)•需要硬件设备(路由器或者网卡)   -NEWT/ATC/ ...

  10. 【Git版本控制】Idea中设置Git忽略对某些文件的版本追踪

    在Idea中有些本地文件无需与远程库同步,仅是本地使用.此时就需要将这些文件加入到Git的版本忽略中来. 设置步骤 1.搜索插件 .ignore,并安装 2.增加.gitignore文件 3.配置相应 ...