【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)
注意:复现代码时,确保 VS2022 使用 C17/20 标准以支持现代特性。 克隆对象的效率革命 1. 模式定义与用途 核心思想 原型模式:通过复制现有对象(原型)来创建新对象,而非通过new构造。关键用…...
深入 Vue.js 组件开发:从基础到实践
深入 Vue.js 组件开发:从基础到实践 Vue.js 作为一款卓越的前端框架,其组件化开发模式为构建高效、可维护的用户界面提供了强大支持。在这篇博客中,我们将深入探讨 Vue.js 组件开发的各个方面,从基础概念到高级技巧,助…...
maven导入spring框架
在eclipse导入maven项目, 在pom.xml文件中加入以下内容 junit junit 3.8.1 test org.springframework spring-core ${org.springframework.version} org.springframework spring-beans ${org.springframework.version} org.springframework spring-context ${org.s…...
数据守护者:备份文件的重要性与自动化实践策略
在数字化浪潮席卷全球的今天,数据已成为企业运营和个人生活中不可或缺的核心资源。无论是企业的财务报表、客户资料,还是个人的家庭照片、工作文档,这些数据都承载着巨大的价值。然而,数据丢失的风险无处不在,硬件故障…...
MyBatis @Param 注解详解:指定的参数找不到?
MyBatis Param 注解详解 1. Param 注解的作用 Param 注解用于显式指定方法参数的名称,让 MyBatis 在 SQL 映射文件(XML)或注解中通过该名称访问参数。 核心场景: 方法有多个参数时,避免参数名丢失或混淆。参数为简单…...
【项目日记(八)】内存回收与联调
前言 我们前面实现了三层缓存申请的过程,并完成了三层缓存申请过程的联调!本期我们来介绍三层的缓存的回收机制以及三层整体联调释放的过程。 目录 前言 一、thread cache 回收内存 二、central cache 回收内存 • 如何确定一个对象对应的span • …...
性能测试监控工具jmeter+grafana
1、什么是性能测试监控体系? 为什么要有监控体系? 原因: 1、项目-日益复杂(内部除了代码外,还有中间件,数据库) 2、一个系统,背后可能有多个软/硬件组合支撑,影响性能的因…...
016.3月夏令营:数理类
016.3月夏令营:数理类: 中国人民大学统计学院: http://www.eeban.com/forum.php?modviewthread&tid386109 北京大学化学学院第一轮: http://www.eeban.com/forum.php?m ... 6026&extrapage%3D1 香港大学化学系夏令营&a…...
CS144 Lab Checkpoint 0: networking warm up
Set up GNU/Linux on your computer 我用的是Ubuntu,按照指导书上写的输入如下命令安装所需的软件包: sudo apt update && sudo apt install git cmake gdb build-essential clang \ clang-tidy clang-format gcc-doc pkg-config glibc-doc tc…...
靶场之路-VulnHub-DC-6 nmap提权、kali爆破、shell反连
靶场之路-VulnHub-DC-6 一、信息收集 1、扫描靶机ip 2、指纹扫描 这里扫的我有点懵,这里只有两个端口,感觉是要扫扫目录了 nmap -sS -sV 192.168.122.128 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.4p1 Debian 10deb9u6 (protoc…...
给没有登录认证的web应用添加登录认证(openresty lua实现)
这阵子不是deepseek火么?我也折腾了下本地部署,ollama、vllm、llama.cpp都弄了下,webui也用了几个,发现nextjs-ollama-llm-ui小巧方便,挺适合个人使用的。如果放在网上供多人使用的话,得接入登录认证才好&a…...
3月5日作业
代码作业: #!/bin/bash# 清空目录函数 safe_clear_dir() {local dir"$1"local name"$2"if [ -d "$dir" ]; thenwhile true; doread -p "检测到 $name 目录已存在,请选择操作: 1) 清空目录内容 2) 保留目…...
【MySQL】增删改查
目录 一、新增(Create) 单行数据 全列插入 多行数据 指定列插入 插入时间 二、查询(Retrieve) 全列查询 指定列查询 查询字段为表达式 别名 去重:DISTINCT 排序:ORDER BY 条件查询࿱…...
【三维生成】StarGen:基于视频扩散模型的可扩展的时空自回归场景生成
标题:《StarGen: A Spatiotemporal Autoregression Framework with Video Diffusion Model for Scalable and Controllable Scene Generation》 项目:https://zju3dv.github.io/StarGen 来源:商汤科技、浙大CAD、Tetras.AI 文章目录 摘要一、…...
线反转法实现矩形键盘按键识别
由于行、列线为多键共用,各按键彼此将相互发 生影响,必须将行、列线信号配合起来并作适当的处 理,才能确定闭合键的位置。 线反转法 第1步:列线输出为全低电平,则行线中电平由高变低 的所在行为按键所在行。 第2步&…...
在 Element Plus 的 <el-select> 组件中,如果需要将 <el-option> 的默认值设置为 null。 用于枚举传值
文章目录 引言轻松实现 `<el-option>` 的默认值为 `null`I 实现方式监听清空事件 【推荐】使用 v-model 绑定 null添加一个值为 null 的选项处理 null 值的显示引言 背景:接口签名规则要求空串参与,空对象不参与签名计算 // 空字符串“” 参与签名组串,null不参与签…...
大白话面试中应对自我介绍
在面试中,自我介绍是开场的关键环节,它就像你递给面试官的一张“个人名片”,要让面试官快速了解你并对你产生兴趣。下面详细讲讲应对自我介绍的要点及回答范例。 一、自我介绍的时间把控 一般面试中的自我介绍控制在1 - 3分钟比较合适。时间…...
Pytorch构建LeNet进行MNIST识别 #自用
LeNet是一种经典的卷积神经网络(CNN)结构,由Yann LeCun等人在1998年提出,主要用于手写数字识别(如MNIST数据集)。作为最早的实用化卷积神经网络,LeNet为现代深度学习模型奠定了基础,…...
元宇宙崛起:区块链与金融科技共绘数字新世界
文章目录 一、引言二、元宇宙与区块链的深度融合三、区块链在元宇宙金融中的应用四、金融科技在元宇宙中的创新应用五、面临的挑战与机遇《区块链与金融科技》亮点内容简介获取方式 一、引言 随着科技的飞速发展,元宇宙概念逐渐走进人们的视野,成为数字…...
React Native 实现滑一点点内容区块指示器也滑一点点
效果图如上,内容滑一点点,指示器也按比例话一点点,列表宽度跟数据有关。 实现思路如下: 1.监听列表滑动事件,获取列表横向滑动距离,假设为A; 2.获取列表的宽度,及列表可滑动的宽度…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
