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

C++ 设计模式——原型模式

原型模式

    • 原型模式
      • 主要组成部分
      • 原型模式的使用步骤
      • 原型模式的 UML 图
      • 原型模式 UML 图解析
      • 优点和缺点
      • 适用场景
      • 总结

原型模式

原型(Prototype)模式是一种创建型模式。原型模式通过(原型对象)克隆出对个一模一样的对象。实际上,该模式与其说是一种设计模式,不如说是一种创建对象的方法(对象克隆),尤其是创建给定类的对象(实例)过程很复杂(例如,要设置许多成员变量的值)时,适用这种设计模式就比较合适。

引入“原型”(Prototype)模式的定义:用原型实例指定创建对象的类型,并且通过复制这些原型创建新的对象。简单来说,就是通过克隆来创建新的对象实例。

主要组成部分

  • 原型接口 (Prototype Interface):定义一个克隆方法,通常是 clone(),用于复制当前对象的实例。
  • 具体原型类 (Concrete Prototype):实现原型接口,提供具体的克隆实现。每个具体原型类都可以被克隆以创建新对象。
  • 客户端 (Client):使用原型对象来创建新对象。客户端通过调用原型的克隆方法来获得新对象,而不是直接使用构造函数。

原型模式的使用步骤

  1. 定义原型接口

    创建一个包含克隆方法的抽象类 Monster

    //怪物父类
    class Monster
    {
    public://构造函数Monster(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}virtual ~Monster() {} //做父类时析构函数应该为虚函数public:virtual Monster* clone() = 0; //具体的实现在子类中进行protected: //可能被子类访问的成员,用protected修饰//怪物属性int m_life;    //生命值int m_magic;   //魔法值int m_attack;  //攻击力
    };
    
  2. 实现具体原型类

    创建具体的怪物类,继承自 Monster,并实现 clone() 方法。

    //亡灵类怪物
    class M_Undead :public Monster
    {
    public://构造函数M_Undead(int life, int magic, int attack) :Monster(life, magic, attack){cout << "一只亡灵类怪物来到了这个世界" << endl;}public://拷贝构造函数M_Undead(const M_Undead& tmpobj) :Monster(tmpobj){cout << "调用了M_Undead::M_Undead(const M_Undead& tmpobj)拷贝构造函数创建了一只亡灵类怪物" << endl;}virtual Monster* clone(){return new M_Undead(*this); //触发拷贝构造函数的调用来创建亡灵类怪物}//其他代码略....
    };//元素类怪物
    class M_Element :public Monster
    {
    public://构造函数M_Element(int life, int magic, int attack) :Monster(life, magic, attack){cout << "一只元素类怪物来到了这个世界" << endl;}public://拷贝构造函数M_Element(const M_Element& tmpobj) :Monster(tmpobj) //初始化列表中注意对父类子对象的初始化{cout << "调用了M_Element::M_Element(const M_Element& tmpobj)拷贝构造函数创建了一只元素类怪物" << endl;}virtual Monster* clone(){return new M_Element(*this);}//其他代码略....
    };//机械类怪物
    class M_Mechanic :public Monster
    {
    public://构造函数M_Mechanic(int life, int magic, int attack) :Monster(life, magic, attack){cout << "一只机械类怪物来到了这个世界" << endl;}public://拷贝构造函数M_Mechanic(const M_Mechanic& tmpobj) :Monster(tmpobj){cout << "调用了M_Mechanic::M_Mechanic(const M_Mechanic& tmpobj)拷贝构造函数创建了一只机械类怪物" << endl;}virtual Monster* clone(){return new M_Mechanic(*this);}//其他代码略....
    };
    
  3. 使用客户端

    在客户端代码中,创建原型对象并使用克隆方法生成新对象。

    int main()
    {// 创建原型对象Monster* undead = new M_Undead(100, 50, 20);Monster* element = new M_Element(80, 60, 25);Monster* mechanic = new M_Mechanic(120, 30, 30);// 克隆对象Monster* clonedUndead = undead->clone();Monster* clonedElement = element->clone();Monster* clonedMechanic = mechanic->clone();// 使用克隆对象...// 例如,可以在这里对克隆对象进行操作或输出属性// 清理内存delete undead;delete element;delete mechanic;delete clonedUndead;delete clonedElement;delete clonedMechanic;return 0;
    }
    

原型模式的 UML 图

原型模式的 UML 图

原型模式 UML 图解析

  • 类关系
    • Prototype(原型类):这是一个抽象类,定义了克隆接口(通常是 clone() 方法)。在 UML 图中,对应于 Monster 类。
    • ConcretePrototype(具体原型类):这些是实现了 Prototype 接口的具体类,负责实现克隆逻辑。图中的 M_UndeadM_ElementM_Mechanic 是具体原型类。
  • 稳定与变化
    • 稳定部分Prototype 类(如 Monster)通常保持不变,定义了基本的属性和克隆接口。
    • 变化部分ConcretePrototype 类(如 M_UndeadM_Element 等)是变化的部分,可以根据需求添加新的具体类。
  • 信息隐藏
    • 客户端代码与 Prototype 接口交互,而不需要了解具体的实现细节。这种设计实现了信息隐藏,使得系统更加灵活。
  • 扩展性
    • 新的具体原型类可以通过实现 Prototype 接口来扩展,而不需要修改现有的代码结构,符合开闭原则。

优点和缺点

优点

  • 简化对象创建:通过克隆现有对象,避免了复杂的构造过程,尤其是当对象需要大量初始化参数时。
  • 提高灵活性:客户端不需要了解具体的对象创建逻辑,只需使用原型进行克隆,增强了代码的灵活性和可维护性。
  • 支持动态配置:可以在运行时决定克隆哪种类型的对象,适应性强。

缺点

  • 性能开销:克隆对象可能导致较大的内存开销,特别是在对象较大或复杂时。
  • 深拷贝与浅拷贝:需要明确区分深拷贝和浅拷贝,错误的实现可能导致共享状态问题。
  • 增加复杂性:需要实现克隆方法,可能会增加代码的复杂性,特别是在有多个子类时。

适用场景

  • 对象创建过程复杂:当对象的构造过程非常复杂,涉及多个参数初始化时,使用原型模式可以简化这一过程。
  • 需要大量相似对象:当需要创建大量相似对象时,使用克隆原型可以提高效率。
  • 运行时动态创建:当对象类型在运行时动态决定时,原型模式可以提供灵活的解决方案。
  • 避免构造函数的重复调用:在需要频繁创建相似对象的场景中,原型模式可以避免重复调用构造函数,提高性能。

总结

原型模式通过定义 PrototypeConcretePrototype 的关系,使得对象的克隆过程更加灵活和高效。客户端只需依赖于 Prototype 接口,能够动态创建新的对象实例,增强了系统的可扩展性和可维护性。

相关文章:

C++ 设计模式——原型模式

原型模式 原型模式主要组成部分原型模式的使用步骤原型模式的 UML 图原型模式 UML 图解析优点和缺点适用场景总结 原型模式 原型(Prototype)模式是一种创建型模式。原型模式通过(原型对象)克隆出对个一模一样的对象。实际上&#xff0c;该模式与其说是一种设计模式&#xff0c…...

【Harmony OS 4.0】待办列表案例

src/main/ets/example1/Models.ets // 定义class类数据模型 export class TaskDataModel {// private 私有属性&#xff0c;在类对象外不允许随意更改数据&#xff0c;必须本地初始化。private tasks: Array<string> [早起晨练, 准备早餐, 阅读名著, 学习ArkTs, 玩游戏…...

快速把文件名统计到excel表的方法

文件名统计到EXCEL表&#xff0c;这似乎很多人都没听说过&#xff0c;因为它与EXCEL表格不沾边&#xff0c;那么这个需求如何实现&#xff0c;用到什么方法&#xff0c;今天给大家介绍一个比较实用的方法&#xff0c;它可以把文件名或文件夹的名快速提取并统计到EXCEL表格上去。…...

开源通用验证码识别OCR —— DdddOcr 源码赏析(一)

文章目录 [toc] 前言DdddOcr环境准备安装DdddOcr使用示例 源码分析实例化DdddOcr实例化过程 分类识别分类识别过程 未完待续 前言 DdddOcr 源码赏析 DdddOcr DdddOcr是开源的通用验证码识别OCR 官方传送门 环境准备 安装DdddOcr pip install ddddocr使用示例 示例图片如…...

上升ECMAScript性能优化技巧与陷阱(下)

4. 深拷贝和浅拷贝的选择不当 在JavaScript中&#xff0c;对象是通过引用传递的&#xff0c;这意味着当你将一个对象赋值给另一个变量时&#xff0c;你实际上是在传递对象的引用&#xff0c;而不是对象本身。这导致了一个常见的问题&#xff1a;当你修改一个对象的属性时&…...

用7EPhone云手机进行TikTok的矩阵运营

“根据市局机构Statista发布的报告显示&#xff0c;截至2024年4月&#xff0c;TikTok全球下载量超过49.2亿次&#xff0c;月度活跃用户数超过15.82亿。TikTok的流量受欢迎程度可想而知&#xff0c;也一跃成为了全球第五大最受欢迎的社交APP。” 人群密集的地方社区也是适合推广…...

谷歌浏览器下载文件被阻止怎么解除

在工作生活中&#xff0c;我们会使用谷歌浏览器下载各种各样的文件&#xff0c;不过偶尔会遇到文件下载被阻止的情况。为了解决这一问题&#xff0c;本文为大家分享了实用的措施建议&#xff0c;一起来了解一下吧。&#xff08;本文由https://chrome.cmrrs.com/站点的作者进行编…...

apt E: 无法定位软件包 winehq-stable

执行了 添加wine源 wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources还需要执行 更新源 apt update...

P2460[SDOI2007] 科比的比赛

第一次做洛谷系列&#xff0c;紧张&#xff0c;请多关照哦 题目传送门&#xff1a;[SDOI2007] 科比的比赛 - 洛谷 思路分析 这道题大概题意是给定我们的主人公 Kobe Bryant 的 mm 个对手&#xff0c;nn 场比赛相对应的获胜概率。求 Kobe Bryant 最大全部获胜概率和打败对手能…...

linux学习--第二天

--Linux文件系统 -显示文件命令 cat 1. cat -b 文件&#xff1a;从1开始对非空输出行编号 2. cat -n 文件&#xff1a;从1开始对所有行编号 3. cat -s 文件&#xff1a;将连续多行空白行合并 more&#xff08;显示一屏文本内容&#xff09; 1. more -num 文件&#xff…...

使用 Flask、Celery 和 Python 实现每月定时任务

为了创建一个使用 Flask、Celery 和 Python 实现的每月定时任务&#xff0c;我们需要按照以下步骤进行&#xff1a; 1.安装必要的库 我们需要安装 Flask、Celery 和 Redis&#xff08;作为消息代理&#xff09;。我们可以使用 pip 来安装它们&#xff1a; bash复制代码 ​ p…...

【c语言】整数在内存中的储存(大小端字节序)

整数在内存中的储存&#xff08;大小端字节序&#xff09; 1.整数在内存中的储存 2.大小端字节序 3.整数在内存中储存例子 4.字节序判断 5.死循环现象 文章目录 整数在内存中的储存&#xff08;大小端字节序&#xff09;整数在内存中的储存大小端字节序什么是大小端为什么会有…...

浅谈SIMD、向量化处理及其在StarRocks中的应用

前言 单指令流多数据流(SIMD)及其衍生出来的向量化处理技术已经有了相当的历史&#xff0c;并且也是高性能数据库、计算引擎、多媒体库等组件的标配利器。笔者在两年多前曾经做过一次有关该主题的内部Geek分享&#xff0c;但可能是由于这个topic离实际研发场景比较远&#xff0…...

【ML】Image Augmentation)的作用、使用方法及其分类

图像增强&#xff08;Image Augmentation&#xff09;的作用、使用方法及其分类 1. 图像增强的定义2. 图像增强的作用3. 什么时候使用图像增强&#xff1f;4. 图像增强详细方法分类梳理4.1 图像增强方法列表4.2 边界框增强方法5. 参考资料 yolov3&#xff08;一&#xff1a;模型…...

设计模式六大原则(一)--单一职责原则

1. 简介 1.1. 概述 一个类或模块应该只负责完成一项任务或承担一个责任。如果一个类或模块承担了多个职责,那么当需要修改其中一个职责的功能时,就可能会对其他职责产生影响,从而导致代码耦合度增加,维护起来更加困难。 1.2. 主要特点 单一职责原则(Single Responsibi…...

c语言学习,malloc()函数分析

1&#xff1a;malloc() 函数说明&#xff1a; 申请配置size大小内存空间 2&#xff1a;函数原型&#xff1a; void *malloc(size_t size) 3&#xff1a;函数参数&#xff1a; 参数size&#xff0c;为申请内存大小 4&#xff1a;返回值&#xff1a; 配置成功则返回指针&#…...

【运维项目经历|041】上云项目-物理机迁移到阿里云

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 ​ 🏅阿里云ACE认证高级工程师 ​ 🏅阿里云开发者社区专家博主 💊交流社区:CSDN云计算交流社区欢迎您的加入! 目录 项目名称 项目背景 项目目标 项…...

分组并合并其它列的非空值 --Excel难题#83

Excel第1列是分类&#xff0c;第2-42列是平行的多个数据项列&#xff0c;下表用部分列示例。数据有X或null两种情况&#xff0c;同一个分类的同一列数据偶尔有重复。 ABCDE1IDCriteria1Criteria2Criteria3Criteria42FirstValueX3FirstValueX4FirstValueX5FirstValueX6SecondVa…...

VM相关配置及docker

NAT——VMnet8网卡 桥接——WLAN/网线 仅主机——VMnet1网卡 docker与虚拟机的区别 启动docker服务 systemctl start docker 重启 systemctl start docker关闭docker服务 systemctl stop docker.servicedocker的两大概念 镜像&#xff1a;images&#xff0c;应用程序的静态文…...

Redis中Set数据类型常用命令

目录 1. 添加元素 2. 移除元素 3. 检查成员是否存在 4. 获取集合成员 5. 获取集合成员数量 6. 随机获取集合中的一个成员 7. 集合运算 8. 集合的移值 9. 提供集合的随机元素 在Redis中&#xff0c;Set是一种无序且不重复的字符串集合。 1. 添加元素 SADD key member [member ..…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...