当前位置: 首页 > article >正文

【C++设计模式】第五篇:原型模式(Prototype)

注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。

克隆对象的效率革命


1. 模式定义与用途​

核心思想​

  • ​原型模式:通过复制现有对象​(原型)来创建新对象,而非通过new构造。​
  • 关键用途:
    1.减少初始化开销:适用于创建成本高的对象(如数据库连接)。
    2.​动态配置对象:运行时通过克隆生成预设配置的实例。

经典场景​

  • 游戏开发:批量生成相同属性的敌人或道具。
  • 文档编辑:复制带格式的文本段落。

2. 模式结构解析​

UML类图

+---------------------+          +---------------------+  
|    Prototype        |          |       Client        |  
+---------------------+          +---------------------+  
| + clone(): Prototype|<>------->| - prototype: Prototype  
+---------------------+          +---------------------+  ^  |  
+---------------------+  
| ConcretePrototype   |  
+---------------------+  
| + clone()           |  
+---------------------+  

角色说明​

  • Prototype:抽象接口,声明克隆方法 clone()
  • ConcretePrototype:具体原型类,实现克隆逻辑。
  • Client:通过调用 clone() 创建新对象。

3. 简单示例:基础克隆实现

#include <memory>  // 抽象原型接口  
class Enemy {  
public:  virtual ~Enemy() = default;  virtual std::unique_ptr<Enemy> clone() const = 0;  virtual void attack() const = 0;  
};  // 具体原型:骷髅战士  
class SkeletonWarrior : public Enemy {  
public:  std::unique_ptr<Enemy> clone() const override {  return std::make_unique<SkeletonWarrior>(*this); // 调用拷贝构造函数  }  void attack() const override {  std::cout << "骷髅战士挥舞骨刀!\n";  }  
};  // 使用克隆  
auto original = std::make_unique<SkeletonWarrior>();  
auto clone = original->clone();  
clone->attack();  // 输出:骷髅战士挥舞骨刀!  

4. 完整代码:原型管理器与深拷贝优化

场景:游戏敌人原型注册与批量生成

#include <iostream>  
#include <unordered_map>  
#include <memory>  
#include <string>  // 抽象敌人原型  
class Enemy {  
public:  virtual ~Enemy() = default;  virtual std::unique_ptr<Enemy> clone() const = 0;  virtual void spawn() const = 0;  virtual void setHealth(int health) = 0;  
};  // 具体原型:火焰恶魔  
class FireDemon : public Enemy {  
public:  FireDemon(int health, const std::string& color)  : health_(health), color_(color) {}  std::unique_ptr<Enemy> clone() const override {  return std::make_unique<FireDemon>(*this);  }  void spawn() const override {  std::cout << "生成" << color_ << "火焰恶魔(生命值:" << health_ << ")\n";  }  void setHealth(int health) override {  health_ = health;  }  private:  int health_;  std::string color_;  
};  // 原型管理器(注册表)  
class PrototypeRegistry {  
public:  void registerPrototype(const std::string& key, std::unique_ptr<Enemy> prototype) {  prototypes_[key] = std::move(prototype);  }  std::unique_ptr<Enemy> createEnemy(const std::string& key) {  auto it = prototypes_.find(key);  if (it != prototypes_.end()) {  return it->second->clone();  }  return nullptr;  }  private:  std::unordered_map<std::string, std::unique_ptr<Enemy>> prototypes_;  
};  // 客户端代码  
int main() {  PrototypeRegistry registry;  // 注册原型  registry.registerPrototype("red_demon", std::make_unique<FireDemon>(100, "红色"));  registry.registerPrototype("blue_demon", std::make_unique<FireDemon>(80, "蓝色"));  // 批量生成敌人  auto enemy1 = registry.createEnemy("red_demon");  auto enemy2 = registry.createEnemy("blue_demon");  auto enemy3 = registry.createEnemy("red_demon");  enemy1->spawn();  // 生成红色火焰恶魔(生命值:100)  enemy2->spawn();  // 生成蓝色火焰恶魔(生命值:80)  enemy3->setHealth(50);  enemy3->spawn();  // 生成红色火焰恶魔(生命值:50)  
}  

5. 优缺点分析

优点​​缺点
​避免重复初始化复杂对象需正确处理深拷贝(尤其含指针成员时)
动态添加/删除原型配置每个类需实现克隆方法,增加代码量
与工厂模式结合扩展性强对简单对象可能得不偿失

6. 调试与优化策略

调试技巧(VS2022)​​

1.深拷贝验证

  • 在拷贝构造函数中设置断点,观察成员变量是否被正确复制。
  • 使用 ​内存断点​ 检测指针成员是否被重复释放。

2.​原型注册表检查

  • 输出注册表的键列表,确认原型是否成功注册。
for (const auto& pair : prototypes_) {  std::cout << "已注册原型: " << pair.first << "\n";  
}  

性能优化​

1.原型预初始化

  • 在程序启动时预加载常用原型,减少运行时开销。

2.浅拷贝优化

  • 对只读数据成员使用浅拷贝(需确保生命周期安全)。
class CheapToCopyEnemy : public Enemy {  
private:  const Texture* sharedTexture_;  // 只读资源,浅拷贝  
};  

相关文章:

【C++设计模式】第五篇:原型模式(Prototype)

注意&#xff1a;复现代码时&#xff0c;确保 VS2022 使用 C17/20 标准以支持现代特性。 克隆对象的效率革命 1. 模式定义与用途​ ​ 核心思想​ ​原型模式&#xff1a;通过复制现有对象​&#xff08;原型&#xff09;来创建新对象&#xff0c;而非通过new构造。​关键用…...

51单片机课综合项目

1、按键控制蜂鸣器实验 1、实验现象&#xff1a;下载程序后&#xff0c;按下K1键蜂鸣器发声一次&#xff0c;按下K2键&#xff0c;蜂鸣器连续发声&#xff0c;再次按下K2键&#xff0c;发声取消 2、使用到的外设模块:蜂鸣器模块beep 独立按键模块 key 3、编程框架&#xff08;…...

【最大半连通子图——tarjan求最大连通分量,拓扑排序,树形DP】

题目 分析 最大连通分量肯定是满足半连通分量的要求&#xff0c;因此tarjan。 同时为了简化图&#xff0c;我们进行缩点&#xff0c;图一定变为拓扑图。 我们很容易看出&#xff0c;只要是一条不分叉的链&#xff0c;是满足条件的。 于是我们按照拓扑序不断树形DP 建边注意…...

一周学会Flask3 Python Web开发-在模板中渲染WTForms表单视图函数里获取表单数据

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 为了能够在模板中渲染表单&#xff0c;我们需要把表单类实例传入模板。首先在视图函数里实例化表单类LoginForm&#xff0c;然…...

DeepSeek R1助力,腾讯AI代码助手解锁音乐创作新

目录 1. DeepSeekR1模型简介2. 歌词创作流程2.1 准备工作2.2 歌词生成技巧 3. 音乐制作环节3.1 主流AI音乐生成平台 4. 歌曲欣赏5. 总结展望 1. DeepSeekR1模型简介 腾讯AI代码助手最新推出的DeepSeekR1模型不仅在代码生成方面表现出色&#xff0c;其强大的自然语言处理能力也…...

用户空间与内核空间切换机制详解

用户空间与内核空间切换机制详解 一、切换触发条件 用户态与内核态的切换由以下三类事件触发: ‌系统调用‌ 用户程序主动通过int 0x80(x86)或ecall(RISC-V)等指令发起系统调用,请求内核服务(如文件读写、进程创建等)。此时CPU自动进入内核态处理请求,完成后返回用户…...

【微信小程序】每日心情笔记

个人团队的比赛项目&#xff0c;仅供学习交流使用 一、项目基本介绍 1. 项目简介 一款基于微信小程序的轻量化笔记工具&#xff0c;旨在帮助用户通过记录每日心情和事件&#xff0c;更好地管理情绪和生活。用户可以根据日期和心情分类&#xff08;如开心、平静、难过等&#…...

为AI聊天工具添加一个知识系统 之135 详细设计之76 通用编程语言 之6

本文要点 要点 通用编程语言设计 本设计通过三级符号系统的动态映射与静态验证的有机结合&#xff0c;实现了从文化表达到硬件优化的全链路支持。每个设计决策均可在[用户原始讨论]中找到对应依据&#xff0c;包括&#xff1a; 三级冒号语法 → 提升文化符号可读性圣灵三角…...

前端基础之组件

组件&#xff1a;实现应用中局部功能代码和资源的集合 非单文件组件 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"…...

spring boot整合flyway实现数据的动态维护

1、简单介绍一下flyway Flyway 是一款开源的数据库版本控制工具&#xff0c;主要用于管理数据库结构的变更&#xff08;如创建表、修改字段、插入数据等&#xff09;。它通过跟踪和执行版本化的迁移脚本&#xff0c;帮助团队实现数据库变更的自动化。接下来简单介绍一下flyway…...

通往 AI 之路:Python 机器学习入门-线性代数

2.1 线性代数&#xff08;机器学习的核心&#xff09; 线性代数是机器学习的基础之一&#xff0c;许多核心算法都依赖矩阵运算。本章将介绍线性代数中的基本概念&#xff0c;包括标量、向量、矩阵、矩阵运算、特征值与特征向量&#xff0c;以及奇异值分解&#xff08;SVD&…...

Matlab中的均值函数mean

今天调了一个代码里的bug&#xff0c;根源居然是mean函数的使用细节没留意到~ 具体来说&#xff0c;写一个类似k均值聚类那样的程序&#xff0c;交替迭代&#xff0c;其中有一部是使用mean求一堆向量的均值&#xff0c;这些向量存在一个矩阵里&#xff0c;每行对应一个向量。若…...

数据结构知识学习小结

一、动态内存分配基本步骤 1、内存分配简单示例&#xff1a; 个人对于示例的理解&#xff1a; 定义一个整型的指针变量p&#xff08;着重认为它是一个“变量”我觉得可能会更好理解&#xff09;&#xff0c;这个变量用来存地址的&#xff0c;而不是“值”&#xff0c;malloc函…...

高精算法的用法及其优势

高精度问题是指当数据的位数非常大&#xff08;超出标准数据类型的范围&#xff09;时&#xff0c;如何进行计算和存储的问题。常见场景包括大整数的加、减、乘、除、取模等操作。以下是解决高精度问题的常用方法与技巧&#xff1a; 一、数据存储 数组存储 用整型数组存储&am…...

【Spring AOP】_切点类的切点表达式

目录 1. 根据方法签名匹配编写切点表达式 1.1 具体语法 1.2 通配符表达规范 2. 根据注解匹配编写切点表达式 2.1 实现步骤 2.2 元注解及其常用取值含义 2.3 使用自定义注解 2.3.1 编写自定义注解MyAspect 2.3.2 编写切面类MyAspectDemo 2.3.3 编写测试类及测试方法 在…...

多线程-定时任务线程池源码

定时任务线程池 ScheduledThreadPoolExecutor&#xff0c;可以执行定时任务的线程池。这里学习它的基本原理。 定时任务线程池&#xff0c;和普通线程池不同的地方在于&#xff0c;它使用一个延迟队列&#xff0c;延迟队列使用最小堆作为它的数据结构&#xff0c;它会按照任务…...

初次使用 IDE 搭配 Lombok 注解的配置

前言 在 Java 开发的漫漫征程中&#xff0c;我们总会遇到各种提升效率的工具。Lombok 便是其中一款能让代码编写变得更加简洁高效的神奇库。它通过注解的方式&#xff0c;巧妙地在编译阶段为我们生成那些繁琐的样板代码&#xff0c;比如 getter、setter、构造函数等。然而&…...

云服数据存储接口:CloudSever

云服数据存储接口&#xff1a;CloudSever 迷你世界 更新时间: 2024-04-28 19:09:10 具体函数名及描述如下&#xff1a; 序号 函数名 函数描述 1 setOrderDataBykey(...) 设置排行榜中指定键的数值 2 removeOrderDataByKey(...) 删除排行榜中指定键的数值 …...

关于 QPalette设置按钮背景未显示出来 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/146047054 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…...

上传文件到对象存储是选择前端还是后端

对于云上对象存储的上传方式选择&#xff08;前端直传或后端代理上传&#xff09;&#xff0c;需综合考虑安全性、性能、成本、业务需求等因素。 1. 推荐前端直传的场景 适用条件&#xff1a; 大文件上传&#xff08;如视频、大型数据集&#xff09;高并发场景&#xff08;如…...

mysql下载与安装

一、mysql下载&#xff1a; MySQL获取&#xff1a; 官网&#xff1a;www.mysql.com 也可以从Oracle官方进入&#xff1a;https://www.oracle.com/ 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 选择对应的版本和对应的操作系统&#xff…...

Python练习(握手问题,进制转换,日期问题,位运算,求和)

一. 握手问题 代码实现 ans0for i in range(1,51):for j in range(i1,51):if i<7 and j<7:continueelse:ans 1print(ans) 这道题可以看成是50个人都握了手减去7个人没握手的次数 答案&#xff1a;1204 二.将十进制整数拆解 2.1门牌制作 代码实现 ans0for i in ra…...

小程序分类页面

1创建cate分支 2.cate滑动界面布局 获取滑动界面高度 3.获取并渲染一级分类的列表数据 4.渲染二级和三级分类列表 获取二级列表的数据 5.渲染二级分类列表的UI结构 6.动态渲染三级分类列表...

HTML + CSS 题目

1.说说你对盒子模型的理解? 一、是什么 对一个文档进行布局的时候&#xff0c;浏览器渲染引擎会根据标准之一的css基础盒模型&#xff0c;将所有元素表示为一个个矩形的盒子。 一个盒子由四个部分组成: content&#xff0c;padding&#xff0c;border&#xff0c;margin 下…...

计算机视觉|ViT详解:打破视觉与语言界限

一、ViT 的诞生背景 在计算机视觉领域的发展中&#xff0c;卷积神经网络&#xff08;CNN&#xff09;一直占据重要地位。自 2012 年 AlexNet 在 ImageNet 大赛中取得优异成绩后&#xff0c;CNN 在图像分类任务中显示出强大能力。随后&#xff0c;VGG、ResNet 等深度网络架构不…...

Node JS 调用模型Xenova_all-MiniLM-L6-v2实战

本篇通过将句子数组转换为句子的向量表示&#xff0c;并通过平均池化和归一化处理&#xff0c;生成适合机器学习或深度学习任务使用的特征向量为例&#xff0c;演示通过NodeJS 的方式调用Xenova/all-MiniLM-L6-v2 的过程。 关于 all-MiniLM-L6-v2 的介绍&#xff0c;可以参照上…...

React + TypeScript 实战指南:用类型守护你的组件

TypeScript 为 React 开发带来了强大的类型安全保障&#xff0c;这里解析常见的一些TS写法&#xff1a; 一、组件基础类型 1. 函数组件定义 // 显式声明 Props 类型并标注返回值 interface WelcomeProps {name: string;age?: number; // 可选属性 }const Welcome: React.FC…...

ASP.NET Core JWT认证与授权

1.JWT结构 JSON Web Token&#xff08;JWT&#xff09;是一种用于在网络应用之间安全传输声明的开放标准&#xff08;RFC 7519&#xff09;。它通常由三部分组成&#xff0c;以紧凑的字符串形式表示&#xff0c;在身份验证、信息交换等场景中广泛应用。 2.JWT权限认证 2.1添…...

【车规芯片】如何引导时钟树生长方向

12nm车规DFTAPR项目中&#xff0c;我们可以看到&#xff0c;绝大部分的sink都受控于xxxx_tessent_occ_clk_cpu_inst/tessent_persistent_cell_clock_out_mux/C10_ctmi_1这个mux&#xff0c;这是我们DFT设计结果&#xff1a; 这里我们重新打开place的数据 Anchor&#xff0c;也就…...

突破传统:用Polars解锁ICU医疗数据分析新范式

一、ICU数据革命的临界点 在重症监护室&#xff08;ICU&#xff09;&#xff0c;每秒都在产生关乎生死的关键数据&#xff1a;从持续监测的生命体征到高频更新的实验室指标&#xff0c;从呼吸机参数到血管活性药物剂量&#xff0c;现代ICU每天产生的数据量级已突破TB级别。传统…...