C# 设计模式之原型模式

news2024/11/24 17:25:47

总目录


前言

在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在内存中分配了多个一样的类实例对象,然后如果采用工厂模式来创建这样的系统的话,随着产品类的不断增加,导致子类的数量不断增多,反而增加了系统复杂程度,所以在这里使用工厂模式来封装类创建过程并不合适,然而原型模式可以很好地解决这个问题,因为每个类实例都是相同的,当我们需要多个相同的类实例时,没必要每次都使用new运算符去创建相同的类实例对象,此时我们一般思路就是想——只创建一个类实例对象,如果后面需要更多这样的实例,可以通过对原来对象拷贝一份来完成创建,这样在内存中不需要创建多个相同的类实例,从而减少内存的消耗和达到类实例的复用。 然而这个思路正是原型模式的实现方式。


1 基本介绍

  1. 原型模式就是通过复制已有对象来创建新对象,而避免重复进行初始化操作,生产多个克隆对象。
  2. 本质:通过拷贝这些原型对象创建新的对象。
  3. 原型模式中的2个角色:
    • Prototype(原型类):声明一个Clone自身的接口;
    • ConcretePrototype(具体原型类):实现一个Clone自身的操作,使用Clone方法完成对象的创建
  4. 浅拷贝和深拷贝
    • 浅拷贝:通过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)-原型模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1967840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据可视化工具,免费无限制制作报表

许多企业在报表制作上投入了大量资金&#xff0c;使用各种收费软件&#xff0c;往往只能满足基本需求&#xff0c;且操作复杂&#xff0c;让人感到无比头疼。不过最近我发现之前一直在做数据大屏的山海鲸可视化&#xff0c;现在新增了报表功能&#xff0c;不仅各种功能都可以免…

创新食堂管理:采购系统源码与供应链APP开发详解

今天&#xff0c;笔者将从食堂采购系统源码与供应链管理APP开发的角度&#xff0c;探讨如何利用技术创新提升食堂管理效率&#xff0c;并为企业带来更大的价值。 一、食堂采购系统的核心功能与优势 食堂采购系统是指用于管理食堂物资采购流程的软件系统&#xff0c;其核心功能…

《学会 SpringMVC 系列 · 剖析入参处理》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

【C++】巧用缺省参数与函数重载:提升编程效率的秘密武器

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间 本章将分享缺省参数与函数重载相关知识&#xff0c;为了更加深入学习C打下了坚实的基础。本章重点在于缺省参数与函数重载使用前提与注意事项 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1…

[CTFHub]ret2text-入土为安的第十二天

checksec pwn ida fn F5 main 点(_int64)v4 v大小为0x70栈基指针0x8返回地址 secure()

软件测试--python基础

一、python基础 (1)第一个python (2)python解释器 (3)基础语法 ①字面量 什么是字面量 常用的值类型 字符串 ②注释 ③变量 什么是变量 变量的特征 变量的目的是存储运行过程的数据 存储的目的是为了&#xff1a;重复使用 ④数据类型 type()语句 变量有类型吗&#xff1f;…

如何选择高品质SD存储卡—高耐用度、防水、防动、抗冲击

SD卡&#xff08;Secure Digital Memory Card&#xff09;是一种广泛使用的存储器件&#xff0c;因其快速的数据传输速度、可热插拔的特性以及较大的存储容量&#xff0c;广泛应用于各种场景&#xff0c;例如在便携式设备如智能手机、平板电脑、运动相机等&#xff0c;用于存储…

68.游戏分析工具设计以及更改辅助中存在的界面问题

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;67.利用FreeLibrary函数实现无痕注入的核心代码 分析工具主要做的是 游戏公共内容分析&…

【前端 · 面试 】TCP 总结(一)—— 概述

最近我在做前端面试题总结系列&#xff0c;感兴趣的朋友可以添加关注&#xff0c;欢迎指正、交流。 争取每个知识点能够多总结一些&#xff0c;至少要做到在面试时&#xff0c;针对每个知识点都可以侃起来&#xff0c;不至于哑火。 image 前言 我们常常会听到“ TCP 三次握手、…

注册中心--Eureka

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;Spring Cloud实战&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1.项目问题 2.解决URL问题 2.1解决思路 2.2注册中心 2.3 CAP理…

LeetCode3. 无重复字符的最长子串(java实现)

今天分享的题目是LeetCode3. 无重复字符的最长子串&#xff0c;来看题目描述&#xff1a; 无重复的最长子串&#xff0c;题目有可能有些小伙伴没读太懂&#xff0c;其实就是找到不重复的最长子串&#xff0c;比如eg3&#xff0c;pwwk&#xff0c;那么w出现了两次就不符合要求。…

SpringBoot中的server.context-path

一、问题引入 书接上回&#xff0c;SpringBoot 在 idea中的 .idea和 .iml文件-CSDN博客&#xff0c;我在boot-test的测试项目中使用的 SpringBoot版本为 1.3.5.RELEASE&#xff0c;新项目 cps-task中使用的版本为 2.4.8&#xff0c;造成了连接异常&#xff0c;问题很好解决&…

一文看懂Java反射、注解、UML图和Lambda表达式

反射 定义: 反射是 java 开发语言的特征之一&#xff0c;它允许 java 程序对自身进行检查(自审)&#xff0c;并能直接操作程序内部属性&#xff0c;即就是将类中的各种成分映射成一个 java 对象&#xff0c;利用反射技术可以对一个类进行解剖&#xff0c;将各个组成部分映射成…

c++STL容器中vector的使用,模拟实现及迭代器使用注意事项和迭代器失效问题

目录 前言&#xff1a; 1.vector的介绍及使用 1.2 vector的使用 1.2 1 vector的定义 1.2 2 vector iterator&#xff08;迭代器&#xff09;的使用 1.2.3 vector 空间增长问题 1.2.4 vector 增删查改 1.2.5vector 迭代器失效问题。 2.vector模拟实现 2.1 std::vect…

RAG 革命:NVIDIA 工作站如何成为企业 AI 的秘密武器

在深圳的一家科技初创公司&#xff0c;首席技术官李梅正在向她的团队展示一个令人兴奋的新项目。“看这个&#xff0c;” 她指着屏幕上的实时演示说&#xff0c;“我们刚刚用公司的技术文档训练了一个 AI 助手&#xff0c;它现在可以回答任何关于我们产品的问题&#xff0c;而且…

鸿蒙系统开发【网络管理】

网络管理 介绍 此Demo展示如何查询网络详情、域名解析、网络状态监听等功能。 效果预览&#xff1a; 使用说明&#xff1a; 1.启动应用&#xff0c;在点击检查网络、网络详情、网络连接信息后&#xff0c;展示对应的信息&#xff1b; 2.在域名解析的模块下&#xff0c;输入…

一款功能强大的免费开源卸载工具

BCUninstaller&#xff0c;也称为Bulk Crap Uninstaller&#xff08;简称BCU&#xff09;&#xff0c;是一款免费且开源的Windows平台专用程序卸载工具。它的主要功能是帮助用户高效地批量卸载不需要的应用程序和组件&#xff0c;从而优化系统性能。 BCUninstaller功能特点 批…

8.1 tomcat+jdk

接着昨天的 npm run serve 构建项目 npm run build ls ls dist/ vim dist/index.html [rootweb eleme_web]# cd /usr/local/nginx/conf/ [rootweb conf]# ls 将静态的项目移动到nginx中 [rootweb nginx]# cd conf.d/ [rootweb conf.d]# ls qd.conf [rootweb conf.…

有关 AI 与产品经理的三个暴论

最近跟朋友聊 AI 聊得挺多。往往是不管做什么的&#xff0c;凡是跟互联网有联系的&#xff0c;都挺兴奋&#xff0c;都在讨论 AI。 聊着聊着&#xff0c;有三个暴论浮出水面&#xff0c;跟各位分享。暴论归暴论&#xff0c;道理还是在的。 1. AI 带来的新技术&#xff0c;会带…

2024年中国大模型能力评测:谁是AI领域的真王者?

2024年中国大模型能力评测深度解析 随着人工智能技术的飞速发展&#xff0c;中国的大模型正迎来前所未有的机遇与挑战。近期发布的《2024年中国大模型能力评测》报告&#xff0c;揭示了这一领域的最新趋势、发展瓶颈以及未来方向。本文将基于该报告&#xff0c;带您深入了解中国…