C# 设计模式之原型模式
总目录
前言
在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在内存中分配了多个一样的类实例对象,然后如果采用工厂模式来创建这样的系统的话,随着产品类的不断增加,导致子类的数量不断增多,反而增加了系统复杂程度,所以在这里使用工厂模式来封装类创建过程并不合适,然而原型模式可以很好地解决这个问题,因为每个类实例都是相同的,当我们需要多个相同的类实例时,没必要每次都使用new运算符去创建相同的类实例对象,此时我们一般思路就是想——只创建一个类实例对象,如果后面需要更多这样的实例,可以通过对原来对象拷贝一份来完成创建,这样在内存中不需要创建多个相同的类实例,从而减少内存的消耗和达到类实例的复用。 然而这个思路正是原型模式的实现方式。
1 基本介绍
- 原型模式就是通过复制已有对象来创建新对象,而避免重复进行初始化操作,生产多个克隆对象。
- 本质:通过拷贝这些原型对象创建新的对象。
- 原型模式中的2个角色:
- Prototype(原型类):声明一个Clone自身的接口;
- ConcretePrototype(具体原型类):实现一个Clone自身的操作,使用Clone方法完成对象的创建
- 浅拷贝和深拷贝
-
浅拷贝:通过this.MemberWiseClone(),对实例的值类型进行拷贝(包含string类型),对引用类型只拷贝了引用。浅拷贝只对值类型成员进行复制,对于引用类型,只是复制了其引用,并不复制其对象。执行浅拷贝创建的新对象与原来对象共享成员,改变一个对象,另外一个对象的成员也会改变。
-
深拷贝:需要通过反射和序列化来实现,执行深拷贝创建的新对象和原来对象不会共享任何东西,改变一个对象对另外一个对象没有任何影响
-
2 使用场景
对象在创建(new)时,消耗资源过多或繁琐耗时。
本质就是在对象的构造函数中有耗时长或者占用系统资源多的情况,
使用原型模式进行复制对象时,可以省去这些耗时耗力的操作,直接获得对象的具体实例。
最常见的使用场景之一就是对象历史节点的保存,比如在对对象进行操作一次后,进行一次复制保存当前状态(恢复到某一历史状态),可实现撤销操作。
3 实现方式
在现实生活中,也有很多原型设计模式的例子,例如,细胞分裂的过程,一个细胞的有丝分裂产生两个相同的细胞;还有西游记中孙悟空变出后孙的本领和火影忍者中鸣人的隐分身忍术等。
1 抽象的原型类,定义一个复制自己的方法
public abstract class Prototype{//Id 值类型public int Id { get; set; }//Message string类型public string Message { get; set; }//NameList 引用类型public List<string> NameList { get; set; } = new List<string>();//构造函数public Prototype(){}//复制的方法public abstract Prototype Clone();}
2 具体的原型类,需要实现复制自己的方法
//具体的原型类public class ConcretePrototype : Prototype{public ConcretePrototype() : base(){}public override Prototype Clone(){// 调用MemberwiseClone方法实现的是浅拷贝,另外还有深拷贝return (Prototype)this.MemberwiseClone();}}
3 客户端调用
public static void Main(string[] args){// 首先创建一个原型类,并给相关属性赋值Prototype concretePrototype = new ConcretePrototype();concretePrototype.Id = 1;concretePrototype.Message = "消息:AAA";concretePrototype.NameList.Add("Jack");concretePrototype.NameList.Add("Marks");Console.WriteLine($"Id:{concretePrototype.Id}");Console.WriteLine($"Message:{concretePrototype.Message}");Console.WriteLine("NameList:");foreach ( string item in concretePrototype.NameList){Console.WriteLine($"Name:{item}");}Console.WriteLine("\r\n");// 然后通过 实现后的原型类 去 复制出一个对象// 然后给复制出的对象赋值,验证当前浅拷贝对于值类型和引用类型的影响Prototype concretePrototype2 = concretePrototype.Clone();concretePrototype2.Id = 2;concretePrototype2.Message = "消息:BBB";concretePrototype2.NameList[1] = "Jack Ma";Console.WriteLine($"复制的对象 Id:{concretePrototype2.Id}");Console.WriteLine($"复制的对象 Message:{concretePrototype2.Message}");Console.WriteLine("复制的对象 NameList:");foreach (string item in concretePrototype2.NameList){Console.WriteLine($"Name:{item}");}Console.WriteLine("\r\n");Console.WriteLine("更改了复制对象属性的值,对比值类型和类型类型的变化");Console.WriteLine($"Id:{concretePrototype.Id}");Console.WriteLine($"Message:{concretePrototype.Message}");Console.WriteLine("NameList:");foreach (string item in concretePrototype.NameList){Console.WriteLine($"Name:{item}");}Console.ReadLine();}
通过这个实例可以看出浅复制,对值类型和string进行全盘拷贝,对引用类型除string只拷贝了引用地址。
4 深拷贝的实现方式
//原型类[Serializable]public abstract class Prototype{//Id 值类型public int Id { get; set; }//Message string类型public string Message { get; set; }//NameList 引用类型public List<string> NameList { get; set; } = new List<string>();//构造函数public Prototype(){}//复制的方法public abstract Prototype Clone();}//具体的原型类[Serializable]public class ConcretePrototype : Prototype{public ConcretePrototype() : base(){}// 实现深拷贝public override Prototype Clone(){//创建一个内存流MemoryStream ms = new MemoryStream();//创建一个二进制序列化对象BinaryFormatter bf = new BinaryFormatter();//将当前对象序列化写入ms内存流中bf.Serialize(ms, this);//设置流读取的位置ms.Position = 0;//将流反序列化为Object对象return bf.Deserialize(ms) as Prototype;}}
执行深拷贝创建的新对象和原来对象不会共享任何东西,改变一个对象对另外一个对象没有任何影响
4 优缺点分析
-
优点:
- 原型模式向客户隐藏了创建新实例的复杂性
- 原型模式允许动态增加或较少产品类。
- 原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。
- 产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构
-
缺点:
- 每个类必须配备一个克隆方法
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
结语
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。
参考资料:
c#中原型模式详解
C#设计模式(6)-原型模式
相关文章:

C# 设计模式之原型模式
总目录 前言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在内存中…...

美林数据Tempo Talents | 两大资源中心,打造开放、成长型数智人才能力平台
在数字化时代的大潮中,高校作为知识与人才培养的重要阵地,独立分散的课程资源管理方式已无法满足现代教育的需求,而数据资源的分散和碎片化也阻碍了科研和教学工作的深入进行。那么,高校如何打造一个集中、高效的课程与数据资源中…...
IDC权威认可!工业领域最佳实践案例!
近日,IDC发布了《工业领域中数据管理分析服务最佳实践案例》报告,总结行业用户在应用过程中面临的主要挑战和实践路径,并评选最佳实践案例,为行业用户提供了相关的指导建议,供市场参考。星环科技中航电梯数据中台项目入…...

未授权访问漏洞系列详解①!
Redis未授权访问漏洞 Redis 默认情况下,会绑定在 0.0.0.0:6379 ,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的…...

第1天:Python基础语法(五)
正文: 在之前的文章中,我们已经学习了Python的基本语法集合和集合的一些常用操作。 在本篇文章中,我们将继续学习其他类型 字符串格式化 使用操作符%s来实现 ➢ 几个%s就几个变量 ➢ 超过一个变量时,需要用元组%(…...
【c++】用C++制作一个简易windows系统
源码: #include <iostream> #include <cstdlib> // 为了使用system #include<limits> void clearScreen() {system("cls"); }void displayMenu() {clearScreen();std::cout << "1.我的文件" << std::endl;std::…...

常见锁策略
目录 1.乐观锁/悲观锁 2.重量级锁/轻量级锁(轻量重量是站在加锁开销的角度) 3.挂起等待锁/自旋锁 4.公平锁/非公平锁 5.可重入锁与不可重入锁 6.读写锁 synchronized 面试题:是什么偏向锁? 锁的升级: 锁消除&…...

【机器学习】人工神经网络优化方法及正则化技术
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 人工神经网络优化方法及正则化技术1. 引言2. 神经网络优化的基础2.1 损失函数2.…...

Django异步请求和后台管理实战
项目概述 项目实现Ajax异步请求局部刷新使用XAdmin后台模板提供图片上传接口在明细页应用了富文本编辑器在加载图书信息的时候使用LazyLoad(图片懒加载) # 环境 asgiref3.7.2 crispy-bootstrap32024.1 defusedxml0.7.1 diff-match-patch20230430 Djang…...

大奖放送 | AI编程达人秀视频文章征集大赛来啦!
AI Coding,可以有多少种打开玩法?腾讯云AI代码助手是一款辅助编码工具,基于混元大模型,提供技术对话、代码补全、代码诊断和优化等能力,为你生成优质代码,帮你解决技术难题,提升编码效率。 我…...

最新小猫咪PHP加密系统源码V1.4_本地API接口_带后台
小猫咪PHP加密系统历时半年,它再一次迎来更新,更新加密算法(这应该是最后一次更新加密算法了,以后主要更新都在框架功能上面了),适配php56-php74,取消批量加密(一些不可控因素&#…...
a bag of bones
以下是根据你提供的内容制作的5道选择题,包括答案和解析: 1. 短语 "a bag of bones" 通常用来描述什么? - A. 一个恐怖片中的角色 - B. 一个非常瘦弱的人 - C. 一个懒惰的人 - D. 一个穿着比基尼的人 答案:B 解析&#…...

XLT高速线缆自动化测试系统
高速线缆自动化测试系统 随着高速通信的快速发展,对于高速数据通信线缆性能要求日益增高,在其硏发、生产阶段,需要多次测试射频性能。传统人工手动测试存在测试环境搭建复杂、测试效率低、耗时长,特别是多次测试中因为人工测试带…...

微软AI业务最新营收数据情况(2024年7月)
Azure AI 年度经常性收入 (ARR):达到50亿美元客户数量:60,000家平均客户价值 (ACV) 中位数:83,000美元同比增长率:达到了惊人的900% GitHub Copilot 年度经常性收入 (ARR):达到3亿美元客户数量:77,000家…...

canvas绘制表格
canvas绘制表格 最近在为公司产品做技术预研,经理让用canvas做一个表格,于是就有了这篇博客。 我们的数据是后端通过MQTT推送过来的 我在代码中也直接使用了 具体MQTT的实现代码,可见博客 在vue使用MQTT 在这里为了方便实用我直接封装成组件…...

避免溃坝的关键:渗压计在防洪管理中的作用
防洪管理对于保障人民生命财产安全具有重要意义,而溃坝作为防洪管理中的重大风险之一,其防范工作尤为关键。在防洪管理体系中,渗压计作为一种重要的监测工具,发挥着不可替代的作用。本文将深入探讨渗压计在防洪管理中的作用。 实时…...

品牌建设如何助力中小企业突破生存瓶颈?
品牌,不仅仅是一个标志或商标,更是企业的形象、声誉和信誉的体现。品牌的存在是为了使企业区别于其他竞争对手,树立独特的形象,赢得消费者的认可和信任。 品牌的本质是品牌拥有者的产品、服务或其它优于竞争对手的优势能为目标受…...

探索Python FastAPI的Annotated参数设计:提升代码的灵活性与可读性
在现代软件开发中,代码的可读性和灵活性是至关重要的。Python的FastAPI框架以其高性能和易用性而受到开发者的喜爱。FastAPI提供了一种名为Annotated的参数设计方式,它允许开发者以类型注解的形式增强函数参数的定义,从而提升代码的表达力和灵…...

ClickHouse 进阶【建表、查询优化】
1、ClickHouse 进阶 因为上一节部署了集群模式,所以需要启动 Zookeeper 和 ck 集群; 1.1、Explain 基本语法 EXPLAIN [AST | SYNTAX | PLAN | PIPELINE] [setting value, ...] SELECT ... [FORMAT ...] AST:用于查看语法树SYNTAX&#…...
Qt拖拽事件详解及代码实现
Qt拖拽事件详解及代码实现 前言项目描述代码结构简介代码详解 前言 qt拖拽事件是一项非常常用并且非常好用的功能,拖拽实际上是一种信息传递的载体,其目的是将信息从一个对象传递给另一个对象。通过拖拽可以简化文件打开或业务操作流程,qt初…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...

【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...

Qt的学习(二)
1. 创建Hello Word 两种方式,实现helloworld: 1.通过图形化的方式,在界面上创建出一个控件,显示helloworld 2.通过纯代码的方式,通过编写代码,在界面上创建控件, 显示hello world; …...

C++中vector类型的介绍和使用
文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…...