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

创建原型

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. Linux SELinux 使用操作

    Linux SELinux 使用操作 # 修改 SELinux 启动模式.临时生效 命令:setenforce [0|1] 0:转成 permissive 宽容模式: 1:转成 Enforcing 强 ...

  2. 【EasyExcel】使用easyExcel过程中,项目报错的解决集合

    报错:Can not close IO [ERROR] 2019-11-02 13:51:21.210 [ProExportSkuDataJob-1455-TaskThread-1] [com.dma ...

  3. 来迟了,用Python助你叠猫猫,抢618大红包!

    目录: 0 引言 1 环境 2 需求分析 3 前置准备 4 逛店铺流程回顾 5 代码全景展示 6 总结 0 引言 最近叠猫猫的活动可真是十分的火爆,每天小伙伴们为了合猫猫忙的可谓是如火如荼.为啥要叠猫 ...

  4. OpenJDK下SpringBoot使用HttpSession时页面打开卡住

    近期将一个老项目向ARM版的CentOS7移植时,遇到了SpringBoot启动顺利,但访问页面卡住的问题.由于是aarch64架构,因此使用了openjdk,这个项目之前在x86_64环境下一直是用 ...

  5. img error 图片加载失败的最佳方案

    有时候, 当img的src加载失败, 会显示缺省碎片图片,  影响用户体验.  有一个js事件onerror就派上了用场. 它可以在加载失败时, 显示缺省的图片. 它有两种使用方式. 第一种: 使用纯 ...

  6. .NET Core RabbitMQ探索(2)——RabbitMQ的Exchange

    实际上,RabbitMQ的生产者并不会直接把消息发送给队列,甚至生产者都不知道消息是否会被发送给一个队列.对于生产者而言,它们只能把消息发送到Exchange,一个Exchange所完成的工作相当简单 ...

  7. nodejs-翻转算法

    nodejs-翻转算法 /** * Created by moon on 2019/12/14. */ //程序运行完成时一定要有输出语句,本工具才能正确展示运行结果. function abc() ...

  8. 剑指 Offer——2. 替换空格

    题目描述 请实现一个函数,将一个字符串中的每个空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 思路与实现 ...

  9. java SSM 框架 微信自定义菜单 快递接口 SpringMVC mybatis redis shiro ehcache websocket

    A 调用摄像头拍照,自定义裁剪编辑头像,头像图片色度调节B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,快速开发利器)+快速表单构建器 freemaker模版技术 ,0个代码不用写,生成 ...

  10. access truncate

    access int access(const char *pathname, int mode); 确定文件或文件夹的访问权限 //unistd.h #define R_OK 4 /* Test f ...