一,原型模式:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。(包含深度克隆和浅克隆)

主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

先上代码,

PeoplePrototype.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace PrototypePattern
{
/// <summary>
/// 如果序列化报错就加上Serializable这个特性
/// </summary>
[Serializable]
public class PeoplePrototype
{
private static PeoplePrototype _peoplePrototype = null;
private PeoplePrototype()
{
Console.WriteLine("{0}被创建了,线程ID{1}", this.GetType(), Thread.CurrentThread.ManagedThreadId);
} static PeoplePrototype()
{
_peoplePrototype = new PeoplePrototype()
{
Name = "小明",
Id = ,
Dept = new Dept()
{
Id = ,
Name = "技术部"
}
};
}
/// <summary>
/// 克隆一个对象
/// </summary>
/// <returns></returns>
public static PeoplePrototype CreateInstance()
{
PeoplePrototype peoplePrototype = (PeoplePrototype)_peoplePrototype.MemberwiseClone();;
return peoplePrototype;
}
/// <summary>
/// 克隆一个对象
/// </summary>
/// <returns></returns>
public static PeoplePrototype CreateInstanceDeep()
{
PeoplePrototype peoplePrototype = (PeoplePrototype)_peoplePrototype.MemberwiseClone();
//深度克隆,重新实例化一个对象和开辟一个内存,所以克隆的结果指向的地址每次都不一样
//可是这样操作麻烦,我们优化一下
peoplePrototype.Dept = new Dept()
{
Id = ,
Name = "技术部"
};
return peoplePrototype;
} public static PeoplePrototype CreateInstanceSerializa()
{
//通过序列化生成实体
return SerializaUtil.DeepClone<PeoplePrototype>(_peoplePrototype);
} public int Id { get; set; } //值类型保存的是地址
/// <summary>
/// 为什么string也是引用类型不被覆盖?String字符串的值是一个定存的,重新改值会实例化一个新的对象,所以在遍历中不建议使用string,因为损耗性能
/// </summary>
public string Name { get; set; } //为什么string也是引用类型不被覆盖?
public Dept Dept { get; set; } //引用类型保存的是地址,所以克隆出来的值是一样的 } /// <summary>
/// 如果序列化报错就加上Serializable这个特性
/// </summary>
[Serializable]
public class Dept
{
public int Id { get; set; }
public string Name { get; set; }
}
}

SerializaUtil.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks; namespace PrototypePattern
{
/// <summary>
/// 帮助类,创建对象
/// </summary>
public class SerializaUtil
{
/// <summary>
/// 根据对象序列化
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
public static string Serializa(object target)
{
using (MemoryStream stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, target);
return Convert.ToBase64String(stream.ToArray());
}
}
/// <summary>
/// 根据对象类型反序列化,生成新的实体对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="target"></param>
/// <returns></returns>
public static T Derializaable<T>(string target)
{
byte[] targetArray = Convert.FromBase64String(target); using (MemoryStream stream = new MemoryStream(targetArray))
{
return (T)new BinaryFormatter().Deserialize(stream);
}
} /// <summary>
/// 实体对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static T DeepClone<T>(T t)
{
return Derializaable<T>(Serializa(t));
}
}
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace PrototypePattern
{
class Program
{
static void Main(string[] args)
{ Console.WriteLine("---------------------------------------");
PeoplePrototype peoplePrototype1 = PeoplePrototype.CreateInstance();
PeoplePrototype peoplePrototype2 = PeoplePrototype.CreateInstance();
Console.WriteLine("{0},{1}", peoplePrototype1.Name, peoplePrototype1.Id);
Console.WriteLine("{0},{1}", peoplePrototype2.Name, peoplePrototype2.Id); Console.WriteLine("---------------------------------------");
PeoplePrototype peoplePrototype3 = PeoplePrototype.CreateInstance();
PeoplePrototype peoplePrototype4 = PeoplePrototype.CreateInstance();
peoplePrototype3.Name = "测试"; //修改peoplePrototype3,不影响peoplePrototype4的值,证明他们不是同一个引用对象
Console.WriteLine("{0},{1}", peoplePrototype3.Name, peoplePrototype3.Id);
Console.WriteLine("{0},{1}", peoplePrototype4.Name, peoplePrototype4.Id); Console.WriteLine("---------------------------------------");
Console.WriteLine("浅克隆");
PeoplePrototype peoplePrototype5 = PeoplePrototype.CreateInstance();
PeoplePrototype peoplePrototype6 = PeoplePrototype.CreateInstance();
peoplePrototype5.Dept.Name = "测试"; //修改peoplePrototype5的Dept.Name,影响peoplePrototype6的值,证明Dept同一个引用对象
peoplePrototype5.Dept.Id = ; //修改peoplePrototype5的Dept.Id ,影响peoplePrototype6的值,证明Dept同一个引用对象
Console.WriteLine("{0},{1}", peoplePrototype5.Dept.Name, peoplePrototype5.Dept.Id);
Console.WriteLine("{0},{1}", peoplePrototype6.Dept.Name, peoplePrototype6.Dept.Id); Console.WriteLine("---------------------------------------");
Console.WriteLine("深克隆");
PeoplePrototype peoplePrototype7 = PeoplePrototype.CreateInstanceDeep();
PeoplePrototype peoplePrototype8 = PeoplePrototype.CreateInstanceDeep();
peoplePrototype7.Dept.Name = "测试"; //修改peoplePrototype5的Dept.Name,影响peoplePrototype6的值,证明Dept同一个引用对象
peoplePrototype7.Dept.Id = ; //修改peoplePrototype5的Dept.Id ,影响peoplePrototype6的值,证明Dept同一个引用对象
Console.WriteLine("{0},{1}", peoplePrototype7.Dept.Name, peoplePrototype7.Dept.Id);
Console.WriteLine("{0},{1}", peoplePrototype8.Dept.Name, peoplePrototype8.Dept.Id); Console.WriteLine("---------------------------------------");
Console.WriteLine("深克隆");
PeoplePrototype peoplePrototype9 = PeoplePrototype.CreateInstanceSerializa();
PeoplePrototype peoplePrototype10 = PeoplePrototype.CreateInstanceSerializa();
peoplePrototype9.Dept.Name = "测试"; //修改peoplePrototype5的Dept.Name,影响peoplePrototype6的值,证明Dept同一个引用对象
peoplePrototype9.Dept.Id = ; //修改peoplePrototype5的Dept.Id ,影响peoplePrototype6的值,证明Dept同一个引用对象
Console.WriteLine("{0},{1}", peoplePrototype9.Dept.Name, peoplePrototype9.Dept.Id);
Console.WriteLine("{0},{1}", peoplePrototype10.Dept.Name, peoplePrototype10.Dept.Id); Console.WriteLine();
}
}
}

执行结果如下

二,总结下

1,什么是浅克隆和深克隆,看代码运行结果解释

1》浅克隆没有克隆我们对象中的引用类型,如我们的实体PeoplePrototype中的Dept,如下图

可是这个时候我们就会疑惑了,string也是引用类型,为什么也会被克隆呢?

2》我们理解下string的运行机制,string是特殊的引用类型,字符串的值是一个定存的,重新改值会实例化一个新的对象,所以在遍历中不建议使用string,因为损耗性能

string ss = "";
ss = ""; //此时 ss = "33";和ss = "44"; 的存储地址不一样的

3》那Dept引用类型在克隆中的是怎样的逻辑呢?

Dept引用类型在克隆中是他们没有初始化,但是都是指向一个内存空间,所以我们将浅克隆的dept属性更改是会同时更改其他克隆出来的对象的dept属性,如下图

4》浅克隆的值类型不受影响

5》那什么是深克隆呢?如下图结果

深克隆的引用类型互不影响,实现的方法有两种

1,在复制中操作引用类型初始化

        /// <summary>
/// 深克隆一个对象
/// </summary>
/// <returns></returns>
public static PeoplePrototype CreateInstanceDeep()
{
PeoplePrototype peoplePrototype = (PeoplePrototype)_peoplePrototype.MemberwiseClone();
//深度克隆,重新实例化一个对象和开辟一个内存,所以克隆的结果指向的地址每次都不一样
//可是这样操作麻烦,我们优化一下
peoplePrototype.Dept = new Dept()
{
Id = ,
Name = "技术部"
};
return peoplePrototype;
}

2,使用序列化和反序列化创建对象(帮助类SerializaUtil)

        /// <summary>
/// 深克隆一个对象
/// </summary>
/// <returns></returns>
public static PeoplePrototype CreateInstanceSerializa()
{
//通过序列化生成实体
return SerializaUtil.DeepClone<PeoplePrototype>(_peoplePrototype);
}

三,原型模式:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

1》复杂对象的指的是当创建该对象消耗资源过多

2》面临的剧烈变化,比如发邮件,我们需要发N条,但是这N条邮件的对象每个人发送的信息也不同,所以导致实力出的的对象的也不完全一样

3》稳定的接口值得是都是通过同一个方法将该对象发送出去,既是调用方法一般不存在变化,而是对象改变

四,在什么情况下该选择原型模式?

1》是类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,如上结果所示,我们在初始化时消耗过多资源,这是就体现出原型模式的优势

2》是通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式

五,原型模式的浅度克隆和深度克隆是什么意思?

1》浅度复制(Shallow Copy):将原来对象中的所有字段逐个复制到一个新对象,如果字段是值类型,则简单地复制一个副本到新对象,改变新对象的值类型字段不会影响原对象;如果字段是引用类型,则复制的是引用,改变目标对象中引用类型字段的值将会影响原对象。

2》深度复制(Deep Copy):与浅复制不同之处在于对引用类型的处理,深复制将新对象中引用类型字段指向复制过的新对象,改变新对象中引用的任何对象,不会影响到原来的对象中对应字段的内容。

C#设计模式:原型模式(Prototype Pattern)的更多相关文章

  1. C#设计模式——原型模式(Prototype Pattern)

    一.概述 在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定.对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依 ...

  2. 设计模式——原型模式(Prototype Pattern)

    原型模式:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象. UML 图: 原型类: package com.cnblog.clarck; /** * 原型类 * * @author c ...

  3. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

  4. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...

  5. 设计模式系列之原型模式(Prototype Pattern)——对象的克隆

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  6. 二十四种设计模式:原型模式(Prototype Pattern)

    原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象.示例有一个Message实体类,现在要克隆它. MessageModel usin ...

  7. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

  8. 2.6 《硬啃设计模式》第8章 复制不是很难 - 原型模式(Prototype Pattern)

    案例: 某即时战略游戏,你训练出来各种很强的战士. 为了增加游戏的可玩性,增加了一种复制魔法.实施该魔法,可以复制任意的战士. 你会怎样考虑这个设计? 在继续阅读之前,请先认真思考并写出你的设计,这样 ...

  9. python 设计模式之原型模式 Prototype Pattern

    #引入 例子1: 孙悟空拔下一嘬猴毛,轻轻一吹就会变出好多的孙悟空来. 例子2:寄个快递下面是一个邮寄快递的场景:“给我寄个快递.”顾客说.“寄往什么地方?寄给……?”你问.“和上次差不多一样,只是邮 ...

  10. 【UE4 设计模式】原型模式 Prototype Pattern

    概述 描述 使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.如孙悟空猴毛分身.鸣人影之分身.剑光分化.无限剑制 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象, ...

随机推荐

  1. 06Web服务

    1.web开发入门 1.1 引入 软件结构分类: CS结构:客户端和服务器端 特点: 1)必须安装特点的客户端程序 2)服务器端升级,客户端同步升级 BS结构:浏览器和服务器端 特点: 1)不需要安装 ...

  2. 查找目录下指定类型的所有文件(maven 打包提取脚本)

    1 首先想到的是递归遍历目录 筛选出符合条件的文件 dir命令递归遍历目录 /b控制显示格式 /s递归  /ad 只显示目录 dir /b/s .\* 判断文件类型 操作数得用`` rem 取出文件扩 ...

  3. bzoj5518 & loj3046 「ZJOI2019」语言 线段树合并+树链的并

    题目传送门 https://loj.ac/problem/3046 题解 首先问题就是问有多少条路径是给定的几条路径中的一条的一个子段. 先考虑链的做法. 枚举右端点 \(i\),那么求出 \(j\) ...

  4. windows下如何安装pip

    在安装pip前,请确认win系统中已经安装好了python,和easy_install工具 Python完成后 配置环境变量 在环境变量中添加Python目录 (1) 右键点击"计算机&qu ...

  5. 详解JVM内存模型与JVM参数详细配置

    对于大多数应用来说,Java 堆(Java Heap)是Java 虚拟机所管理的内存中最大的一块.Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建. JVM内存结构 由上图可以清楚的看到 ...

  6. Linux命令行工具之vmstat命令

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11484608.html vmstat是一款指定采样周期和次数的功能性监测工具,可以使用它监控进程上下文 ...

  7. kafka集群安装及基本命令行使用

    集群安装 环境介绍 本次安装kafka集群利用的是自带的zooKeeper,其实最好是把kafka和zooKeeper部署在不同的节点上,这样更高可用. 三个节点: kafka1:192.168.56 ...

  8. BZOJ 1596: [Usaco2008 Jan]电话网络 树形DP

    挺经典的,细节需要特别注意一下 Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s& ...

  9. vue概念

    Vue是单向数据流还是双向数据绑定? Vue是单向数据流不是双向数据绑定 Vue的双向数据绑定不过是语法糖(语法糖本质就是一种新的编码方式,并没有给语言增加新的功能.语法糖目的就是为了让代码更易读,更 ...

  10. 凉经-Mozilla Firefox Ltd

    北京谋智火狐信息技术有限公司(北京市东城区建国门华润大厦17层)过去面试的时候感觉电梯好神奇啊!一边的电梯是直达18层以上的,我按了18层准备到了再往下走一层,一个老司机和我说要做另一边的1-17层的 ...