购买域名和服务器多少钱/windows优化大师会员兑换码
文章目录
- 一、引言
- 二、原型模式
- 三、总结
一、引言
与工厂模式相同,原型模式(Prototype)也是创建型模式。原型模式通过一个对象(原型对象)克隆出多个一模一样的对象。实际上,该模式与其说是一种设计模式,不如说是一种创建对象的方法(对象克隆),尤其是创建给定类的对象(实例)过程很复杂(例如,要设置许多成员变量的值)时,使用这种设计模式就比较合适。
二、原型模式
也就是说,原型模式是为了使你能够复制已有对象, 而又无需使代码依赖它们所属的类。
如果你有一个对象, 并希望生成与其完全相同的一个复制品, 你该如何实现呢? 首先, 你必须新建一个属于相同类的对象。 然后, 你必须遍历原始对象的所有成员变量, 并将成员变量值复制到新对象中。
不错! 但有个小问题。 并非所有对象都能通过这种方式进行复制, 因为有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的。直接复制还有另外一个问题。 因为你必须知道对象所属的类才能创建复制品, 所以代码必须依赖该类。 即使你可以接受额外的依赖性, 那还有另外一个问题: 有时你只知道对象所实现的接口, 而不知道其所属的具体类, 比如可向方法的某个参数传入实现了某个接口的任何对象。克隆可能会在父类和子类之间进行,并且可能是动态的,很明显通过父类的拷贝构造函数无法实现对子类对象的拷贝,其实这就是一个多态,我们需要给父类提供一个克隆函数并且是一个虚函数。
仍然使用闯关打怪兽的案例来解释。下面是一个怪兽类。我们想让怪物父类拥有clone
自己的能力。
// 怪物父类
class Monster {
public:// 构造函数Monster(int life, int magic, int attack): m_life(life), m_magic(magic), m_attack(attack) {}virtual ~Monster() {} // 虚析构函数virtual unique_ptr<Monster> clone() const = 0; //cloneprotected: int m_life; // 生命值int m_magic; // 魔法值int m_attack; // 攻击力
};
clone
函数意味着调用该成员函数就会从当前类对象复制出一个完全相同的对象(通过克隆自已来创建出新对象),这当然也是一种创建该类所属对象的方式。这三种怪物实现父类的clone
方法。
// 亡灵类
class M_Undead : public Monster {
public:M_Undead(int life, int magic, int attack) : Monster(life, magic, attack) {cout << "一只亡灵类怪物来到了这个世界" << endl;}unique_ptr<Monster> clone() const override {cout<<" 亡灵类被克隆了 "<<endl;return make_unique<M_Undead>(*this); // 克隆自身}
};// 元素类
class M_Element : public Monster {
public:M_Element(int life, int magic, int attack) : Monster(life, magic, attack) {cout << "一只元素类怪物来到了这个世界" << endl;}unique_ptr<Monster> clone() const override {cout<<" 元素类被克隆了 "<<endl;return make_unique<M_Element>(*this); // 克隆自身}
};// 机械类
class M_Mechanic : public Monster {
public:M_Mechanic(int life, int magic, int attack) : Monster(life, magic, attack) {cout << "一只机械类怪物来到了这个世界" << endl;}unique_ptr<Monster> clone() const override {cout<<" 机械类被克隆了 "<<endl;return make_unique<M_Mechanic>(*this); // 克隆自身}
};
既然是克隆,那么上述M_Undead
、M_Element
、M_Mechanic
中的clone
成员函数的实现体是需要修改的。例如,某个机械类怪物因为被主角砍了一刀失去了100点生命值,导致该怪物对象的m_life
成员变量(生命值)从原来的400变成300,那么调用clone
方法克隆出来的新机械类怪物对象也应该是300
点生命值,所以此时M_Mechanic
类中clone
成员函数中的代码行return new M_Mechanic(400,0,110);
就不合适,因为这样会创建(克隆)出一个400点生命值的新怪物,不符合clone这个成员函数的本意(复制出一个完全相同的对象)。
克隆对象自身实际上是需要调用类的拷贝构造函数的。如果程序员在类中没有定义自已的拷贝构造函数,那么编译器会在必要的时候(但不是一定)合成出一个拷贝构造函数。因此,**在使用原型模式的时候要注意深拷贝和浅拷贝的问题。**下面添加拷贝构造函数。
// 亡灵类
// 拷贝构造函数
M_Undead::M_Undead(const M_Undead& other) : Monster(other) {cout << "亡灵类被拷贝了" << endl;
}
为了方便,我们仅写一个。这里我们需要确保能正确编写拷贝构造函数,这样调用clone
才能正确的克隆出对象。
unique_ptr<Monster> undead = make_unique<M_Undead>(100, 50, 20);
unique_ptr<Monster> undeadClone = undead->clone(); // 克隆亡灵怪物unique_ptr<Monster> element = make_unique<M_Element>(80, 70, 30);
unique_ptr<Monster> elementClone = element->clone(); // 克隆元素怪物unique_ptr<Monster> mechanic = make_unique<M_Mechanic>(120, 40, 50);
unique_ptr<Monster> mechanicClone = mechanic->clone(); // 克隆机械怪物
原型模式将克隆过程委派给被克隆的实际对象。 模式为所有支持克隆的对象声明了一个通用接口, 该接口能够克隆对象, 同时又无需将代码和对象所属类耦合。 通常情况下, 这样的接口中仅包含一个
clone
方法。所有的类对
clone
方法的实现都非常相似。 该方法会创建一个当前类的对象, 然后将原始对象所有的成员变量值复制到新建的类中。 甚至可以复制私有成员变量, 因为绝大部分编程语言都允许对象访问其同类对象的私有成员变量。支持克隆的对象即为原型。 当对象有几十个成员变量和几百种类型时, 对其进行克隆甚至可以代替子类的构造。
原型模式就是能够复制已有的对象,而又无需使代码依赖它们所属的类。换种说法,就是通过已有对象克隆出另一个新的对象,并且克隆这个对象不需要使用构造函数。
原型模式的UML图中,包含两种角色。
- 抽象原型类(Prototype):所有具体原型类的父类,在其中声明克隆方法。这里指Monster类。
- 具体原型类(oncretePrototype):实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。这里指M_Undead类、M_Element类和M_Mechanic类。
引入原型模型的定义:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。简单来说,就是通过克隆来创建新的对象实例。
原型模式结构
- 原型 (Prototype) 接口将对克隆方法进行声明。 在绝大多数情况下, 其中只会有一个名为
clone
克隆的方法。 - 具体原型 (Concrete Prototype) 类将实现克隆方法。 除了将原始对象的数据复制到克隆体中之外, 该方法有时还需处理克隆过程中的极端情况, 例如克隆关联对象和梳理递归依赖等等。
- 客户端 (Client) 可以复制实现了原型接口的任何对象。
原型注册表 (Prototype Registry) 提供了一种访问常用原型的简单方法, 其中存储了一系列可供随时复制的预生成对象。 最简单的注册表原型是一个 名称 → 原型
的哈希表。 但如果需要使用名称以外的条件进行搜索, 你可以创建更加完善的注册表版本。
三、总结
原型模式与工厂方法模式在创建对象时的主要区别在于它们如何处理对象的创建过程和状态复制。
原型模式通过复制现有对象(原型)来创建新对象,新对象的初始状态与原型对象相同,这避免了复杂的设置过程。当对象的内部数据复杂且多变时,原型模式比工厂方法模式更合适,因为它可以直接克隆当前状态,无需额外的设置代码。例如,在游戏中创建一个具有特定状态的怪物分身,使用原型模式可以快速复制这些状态。
工厂方法模式和原型模式在创建对象时都不需要知道具体的类名,但它们的工作方式不同。工厂方法模式通过调用创建接口来创建新对象,而原型模式通过克隆现有对象。如果对象的创建成本较高,或者需要避免复杂的初始化逻辑,原型模式是一个更好的选择。总结来说,两种模式都能解耦对象的创建过程,但原型模式在处理动态和复杂状态的对象时更为高效。
因此,如果对象的内部数据比较复杂且多变并且在创建对象的时候希望保持对象的当前状态,那么用原型模式显然比原型模式更合适。
工厂方法模式与原型模式在创建对象时的异同点:
- 前面范例中创建怪物对象时,这两种模式其实都不需要程序员知道所创建对象所属的类名;
- 工厂方法模式是调用相应的创建接口,例如使用
createMonster
接口来创建新的怪物对象,该接口中采用代码行``new类名(参数)`来完成对象的最终创建工作,这仍旧是属于根据类名来生成新对象; - 型模式是调用例如
clone
(程序员可以修改成任意其他名字)接口来创建新的怪物对象,按照惯例,这个接口一般不带任何参数,以免破坏克隆接口的统一性。该接口中采用的是代码行new类名(*this)
完成对类拷贝构造函数的调用来创建对象,所以这种创建对象的方式是根据现有对象来生成新对象
当然,也可以把原型模式看成是一种特殊的工厂方法模式(工厂方法模式的变体),这也是可以的一把原型对象所属的类本身(例如,M_Undead、M_Element、M_Mechanic)看成是创建克隆对象的工厂,而工厂方法指的自然就是克隆方法(clone)。
有时候原型可以作为备忘录模式的一个简化版本, 其条件是需要在历史记录中存储的对象的状态比较简单, 不需要链接其他外部资源, 或者链接可以方便地重建。原型并不基于继承, 因此没有继承的缺点。 另一方面, 原型需要对被复制对象进行复杂的初始化。 工厂方法基于继承, 但是它不需要初始化步骤。
在大量使用组合模式和装饰模式的设计时,可以通过原型模式来复制复杂结构, 而非从零开始重新构造。
相关文章:

C++设计模式创建型模式———原型模式
文章目录 一、引言二、原型模式三、总结 一、引言 与工厂模式相同,原型模式(Prototype)也是创建型模式。原型模式通过一个对象(原型对象)克隆出多个一模一样的对象。实际上,该模式与其说是一种设计模式&am…...

重学SpringBoot3-Spring WebFlux之SSE服务器发送事件
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ Spring WebFlux之SSE服务器发送事件 1. 什么是 SSE?2. Spring Boot 3 响应式编程与 SSE为什么选择响应式编程实现 SSE? 3. 实现 SSE 的基本步骤3.…...

YOLO即插即用模块---AgentAttention
Agent Attention: On the Integration of Softmax and Linear Attention 论文地址:https://arxiv.org/pdf/2312.08874 问题: 普遍使用的 Softmax 注意力机制在视觉 Transformer 模型中计算复杂度过高,限制了其在各种场景中的应用。 方法&a…...

探索开源语音识别的未来:高效利用先进的自动语音识别技术20241030
🚀 探索开源语音识别的未来:高效利用自动语音识别技术 🌟 引言 在数字化时代,语音识别技术正在引领人机交互的新潮流,为各行业带来了颠覆性的改变。开源的自动语音识别(ASR)系统,如…...

学习路之TP6--workman安装
一、安装 首先通过 composer 安装 composer require topthink/think-worker 报错: 分析:最新版本需要TP8,或装低版本的 composer require topthink/think-worker:^3.*安装后, 增加目录 vendor\workerman vendor\topthink\think-w…...

.NET内网实战:通过白名单文件反序列化漏洞绕过UAC
01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏,主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧,对内网和后渗透感兴趣的朋友们可以订阅该电子报刊,解锁更多的报刊内容。 02基本介绍 03原理分析 在渗透测试和红…...

AI Agents - 自动化项目:计划、评估和分配
Agents: Role 角色Goal 目标Backstory 背景故事 Tasks: Description 描述Expected Output 期望输出Agent 代理 Automated Project: Planning, Estimation, and Allocation Initial Imports 1.本地文件helper.py # Add your utilities or helper functions to…...

Git的.gitignore文件
一、各语言对应的.gitignore模板文件 项目地址:https://github.com/github/gitignore 二、.gitignore文件不生效 .gitignore文件只是ignore没有被追踪的文件,已被追踪的文件,要先删除缓存文件。 # 单个文件 git rm --cached file/path/to…...

网站安全,WAF网站保护暴力破解
雷池的核心功能 通过过滤和监控 Web 应用与互联网之间的 HTTP 流量,功能包括: SQL 注入保护:防止恶意 SQL 代码的注入,保护网站数据安全。跨站脚本攻击 (XSS):阻止攻击者在用户浏览器中执行恶意脚本。暴力破解防护&a…...

深度学习:梯度下降算法简介
梯度下降算法简介 梯度下降算法 我们思考这样一个问题,现在需要用一条直线来回归拟合这三个点,直线的方程是 y w ^ x b y \hat{w}x b yw^xb,我们假设斜率 w ^ \hat{w} w^是已知的,现在想要找到一个最好的截距 b b b。 一条…...

SparkSQL整合Hive后,如何启动hiveserver2服务
当spark sql与hive整合后,我们就无法启动hiveserver2的服务了,每次都要先启动hive的元数据服务(nohup hive --service metastore)才能启动hive,之前的beeline命令也用不了,hiveserver2的无法启动,这也导致我…...

前端路由如何从0开始配置?vue-router 的使用
在 Web 开发中,路由是指根据 URL 的不同部分将请求分发到不同的处理函数或页面的过程。路由是单页应用(SPA, Single Page Application)和服务器端渲染(SSR, Server-Side Rendering)应用中的一个重要概念。 在开发中如何…...

Java中的运算符【与C语言的区别】
目录 1. 算术运算符 1.0 赋值运算符: 1.1 四则运算符: - * / % 【取余与C有点不同】 1.2 增量运算符: - * / % * 【右侧运算结果会自动转换类型】 1.3 自增、自减:、-- 2. 关系运算符 3. 逻辑运算符 3.1 短路求值 3.2 【…...

二、基础语法
入门了解 注释 **作用:**在代码中加一些注释和说明,方便自己或者其他程序员阅读代码 两种格式: 单行注释:// 描述信息 通常放在一行代码的上方,或者一条语句的末尾,对该行代码进行说明 多行注释&#x…...

DB-GPT系列(一):DB-GPT能帮你做什么?
DB-GPT是一个开源的AI原生数据应用开发框架(AI Native Data App Development framework with AWEL and Agents),围绕大模型提供灵活、可拓展的AI原生数据应用管理与开发能力,可以帮助企业快速构建、部署智能AI数据应用,通过智能数据分析、洞察…...

【Python各个击破】numpy
简介 NumPy是一个开源的Python库,它提供了一个强大的N维数组对象和许多用于操作这些数组的函数。它是大多数Python科学计算的基础,包括Pandas、SciPy和scikit-learn等库都建立在NumPy之上。 安装 !pip install numpy导入 import numpy as np用法 # …...

【STM32 Blue Pill编程实例】-4位7段数码管使用
4位7段数码管使用 文章目录 4位7段数码管使用1、7段数码介绍2、硬件准备与接线3、模块配置4、代码实现在本文中,我们将介绍如何将 STM32 Blue Pill开发板与 4 位 7 段数码管连接,并在 STM32CubeIDE 中对其进行编程。 在文章中首先将介绍 4 位 7 段数码管及其与 STM32 Blue Pi…...

[进阶]java基础之集合(三)数据结构
文章目录 数据结构概述常见的数据结构数据结构(栈)数据结构(队列)数据结构(数组)数据结构(链表) 数据结构 概述 数据结构是计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。数据结构是为了更加方便的管理和使用数据,需要结合具体的业…...

《Apache Cordova/PhoneGap 使用技巧分享》
一、引言 在移动应用开发的领域中,Apache Cordova(也被称为 PhoneGap)是一个强大的工具,它允许开发者使用 HTML、CSS 和 JavaScript 等 Web 技术来构建跨平台的移动应用。这种方式不仅能够提高开发效率,还能降低开发成…...

SCP(Secure Copy
SCP(Secure Copy)是Linux系统下基于SSH协议的安全文件传输工具,用于在本地和远程主机间安全、快速地传输文件和目录。SCP命令通过加密传输确保数据的安全性,并且不占用过多系统资源。 SCP的基本用法 基本语法:…...

uniApp 省市区自定义数据
关于自定义省市区选择 其实也是用了 uniApp的内置组件 picker <picker mode"multiSelector" change"bindRegionChange" columnchange"bindMultiPickerColumnChange" :value"valueRegion" :range"multiArray"><v…...

图解Redis 06 | Hash数据类型的原理及应用场景
介绍 Hash 类型特别适合存储对象,例如用户信息等。 String类型也可以用于存储用户信息,Hash与String存储用户信息的区别如下图所示: 内部实现 Hash 类型 的底层数据结构是通过压缩列表(Ziplist)或哈希表ÿ…...

在 Windows 系统上设置 MySQL8.0以支持远程连接
在 Windows 系统上设置 MySQL8.0以支持远程连接的步骤如下: 步骤1: 修改 MySQL 配置文件1. 找到配置文件: MySQL 的配置文件通常为 my.ini,通常位于 C:\ProgramData\MySQL\MySQL Server8.0\(确保查看隐藏文件和文件夹)…...

四种基本的编程命名规范
目前,共有四种基本的编程命名规范,分别是匈牙利命名法、驼峰式命名法、帕斯卡命名法和下划线命名法,其中前三种命名法较为流行。 例如:iMyData是一个匈牙利命名法;myData是一个驼峰式命名法;MyData是一个帕…...

【前端】在 TypeScript 中使用 AbortController 取消异步请求
在 TypeScript 中使用 AbortController 来取消异步请求,尤其是像 fetch 这样的请求,可以提供一种优雅的方式来中止长时间运行的操作。下面是一个详细的步骤说明,展示如何在 TypeScript 中使用 AbortController 取消 fetch 请求。 步骤 1&…...

k8s知识点总结
docker 名称空间 分类 Docker中的名称空间用于提供进程隔离,确保容器之间的资源相互独立。主要分类包括: PID Namespace:进程ID隔离,使每个容器有自己的进程树,容器内的进程不会干扰其他容器或主机上的进程。 NET Nam…...

论文阅读:三星-TinyClick
《Single-Turn Agent for Empowering GUI Automation》 赋能GUI自动化的单轮代理 摘要 我们介绍了一个用于图形用户界面(GUI)交互任务的单轮代理,使用了视觉语言模型Florence-2-Base。该代理的主要任务是识别与用户指令相对应的UI元素的屏幕…...

Windows on ARM上使用sherpa-onnx实现语音识别
Windows on ARM上使用sherpa-onnx实现语音识别 下载模型准备声音文件测试下载模型 模型所在的地址在这里(),通过git命令将模型下载下来 模型:hfd地址 git clone https://hf-mirror.com/csukuangfj/sherpa-onnx-streaming-paraformer-bilingual-zh-en将如下的代码保存成一个…...

Unity 打包AB Timeline 引用丢失,错误问题
1、裁剪 在 link.xml 添加 <assembly fullname"Unity.Timeline" preserve"all"/> 上面这一步我其实做了,但还是不行,各种搜索,不得解,还有创建一个空的Timeline 放到 Resources目录下的,也…...

【Kettle的安装与使用】使用Kettle实现mysql和hive的数据传输(使用Kettle将mysql数据导入hive、将hive数据导入mysql)
文章目录 一、安装1、解压2、修改字符集3、启动 二、实战1、将hive数据导入mysql2、将mysql数据导入到hive 一、安装 Kettle的安装包在文章结尾 1、解压 在windows中解压到一个非中文路径下 2、修改字符集 修改 spoon.bat 文件 "-Dfile.encodingUTF-8"3、启动…...