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

创建原型

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. 机器学习(六)--------神经网络(Neural Networks)

    无论是线性回归还是逻辑回归都有这样一个缺点,即:当特征太多时, 计算的负荷会非常大. 比如识别图像,是否是一辆汽车,可能就需要判断太多像素. 这时候就需要神经网络. 神经网络是模拟人类大脑的神经网络, ...

  2. JVM的内存分配策略

    1.对象优先在Eden区分配大多数情况下,对象在新生代Eden区中分配.当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC. 2.大对象直接进入老年代 所谓的大对象是指,需要大量连续 ...

  3. FilterRegistrationBean注册过滤器探究

    官方定义: A ServletContextInitializer to register Filters in a Servlet 3.0+ container. Similar to the re ...

  4. 【mysql】Mysql的profile的使用 --- Profilling mysql的性能分析工具

    分析SQL执行带来的开销是优化SQL的重要手段. 在MySQL数据库中,可以通过配置profiling参数来启用SQL剖析.该参数可以在全局和session级别来设置.对于全局级别则作用于整个MySQ ...

  5. Ubuntu关机重启后 NVIDIA-SMI 命令不能使用

    问题: 电脑安装好Ubuntu系统后,后续安装了显卡驱动.CUDA.cuDNN等软件,后续一直没有关机.中间系统曾经有过升级,这也是问题所在.系统升级导致内核改变,并可能导致它与显卡驱动不再匹配,所以 ...

  6. wpf 代码设置图片路径(后台和xamll)

    项目中经常使用背景图片,当一个小组共通开发时,路径的选择应该是在项目运行的固定文件夹下 此时,可用代码实现:pack://SiteOfOrigin:,,,/Images/Icons/HomePageB ...

  7. 团队展示&选题 (白衣天使队)

    作业详见此地址:    https://www.cnblogs.com/bbplus/p/11735449.html

  8. windows及linux环境下修改pip的默认镜像源的方法

    1. 在windows环境下 临时修改 使用清华大学的源安装numpy包. pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple ...

  9. Linux 配置Java环境

    下载jdk安装包 安装Java环境之前,首先要到 官网下载地址 下载我们需要的jdk安装包,根据我们Linux系统的位数来选择需要下载的包,我的Linux是64位的,所以我下载的64位的jdk安装包. ...

  10. xenserver 添加和卸载硬盘

                最近在浪潮服务器上安了xenserver系统,创建虚拟机,没注意磁盘超负载就重启了服务导致各种坑,一言难尽,忧伤逆流成河啊,所以准备将各种操作整理总结记录下,持续更新ing~~ ...