【设计模式--原型模式(Prototype Pattern)
一、什么是原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,它的主要目的是通过复制现有对象来创建新的对象,而无需显式地使用构造函数或工厂方法。这种模式允许我们创建一个可定制的原型对象,然后通过复制它来创建新的对象,从而避免了重复构建相似的对象。
在原型模式中,通常有以下几个核心角色:
- 原型(Prototype):定义了一个克隆自己的接口,它是需要复制的对象的抽象表示。
- 具体原型(Concrete Prototype):实现了原型接口,实现了克隆自己的方法。
- 客户端(Client):负责创建新对象,通过克隆已有的原型来获得新对象的副本。
原型模式的优点包括:
- 减少了对象的创建成本:通过克隆已有对象,避免了重新构建相似对象的成本。
- 提高了性能:克隆比创建对象更高效,特别是在初始化成本高的情况下。
- 隐藏了对象的创建细节:客户端不需要知道如何创建对象,只需通过克隆获得所需的对象。
然而,原型模式也有一些缺点:
- 如果对象的构造函数有副作用,那么克隆可能会导致不一致的行为。
- 如果对象层次较深,需要逐层克隆,可能会变得比较复杂。
- 在某些语言或环境中,克隆对象可能需要编写较多的代码。
总之,原型模式适用于需要创建相似对象或对象层次的场景,它提供了一种更高效、灵活的对象创建方式。
二、原型模式的代码样例
以下是一个使用C++实现原型模式的简单示例:
#include <iostream>
#include <string>
#include <unordered_map>// 原型抽象类
class Prototype {
public:virtual Prototype* clone() const = 0;virtual void display() const = 0;
};// 具体原型类A
class ConcretePrototypeA : public Prototype {
public:ConcretePrototypeA(int value) : value(value) {}Prototype* clone() const override {return new ConcretePrototypeA(value);}void display() const override {std::cout << "ConcretePrototypeA with value: " << value << std::endl;}private:int value;
};// 具体原型类B
class ConcretePrototypeB : public Prototype {
public:ConcretePrototypeB(const std::string& name) : name(name) {}Prototype* clone() const override {return new ConcretePrototypeB(name);}void display() const override {std::cout << "ConcretePrototypeB with name: " << name << std::endl;}private:std::string name;
};// 原型管理器
class PrototypeManager {
public:void registerPrototype(const std::string& key, Prototype* prototype) {prototypes[key] = prototype;}Prototype* getPrototype(const std::string& key) {if (prototypes.find(key) != prototypes.end()) {return prototypes[key]->clone();}return nullptr;}private:std::unordered_map<std::string, Prototype*> prototypes;
};int main() {PrototypeManager manager;manager.registerPrototype("prototypeA", new ConcretePrototypeA(100));manager.registerPrototype("prototypeB", new ConcretePrototypeB("PrototypeB"));Prototype* clonedA = manager.getPrototype("prototypeA");if (clonedA) {clonedA->display();delete clonedA;}Prototype* clonedB = manager.getPrototype("prototypeB");if (clonedB) {clonedB->display();delete clonedB;}return 0;
}
在这个示例中,我们定义了一个原型抽象类 Prototype,然后有两个具体的原型类 ConcretePrototypeA 和 ConcretePrototypeB,它们都实现了克隆自己的方法。原型管理器 PrototypeManager 用于管理不同类型的原型对象。
通过原型模式,我们可以注册不同的原型对象,并在需要时通过原型管理器创建它们的克隆,从而实现了对象的复制和创建。这种方式可以避免重复构建相似的对象,提高了效率。
三、使用原型模式需要注意的问题
在使用原型模式时,有几个注意事项需要考虑:
- 深克隆与浅克隆:原型模式涉及克隆对象,而克隆可以分为深克隆和浅克隆。浅克隆只复制对象的值和指针,而不复制指针指向的对象。深克隆会递归地复制对象及其关联的所有对象。在确定克隆的方式时,需要考虑对象间的关系和内存管理。
- 构造函数和初始化:克隆对象不会调用构造函数,它是通过复制现有对象的内部状态来创建新对象。因此,如果在构造函数中进行了某些初始化操作,克隆对象可能会缺少这些初始化。需要确保对象的状态在克隆后正确。
- 单例模式和原型模式的结合:如果一个类同时实现了单例模式和原型模式,就需要特别小心。单例模式要求一个类只有一个实例,而原型模式要求创建新对象。在这种情况下,需要权衡是否要同时支持这两种模式。
- 对象图的复杂性:如果对象之间有复杂的关联关系,如循环引用等,克隆对象可能会导致对象图的复制变得复杂。需要仔细考虑对象之间的关系,以及克隆操作的顺序。
- 性能开销:深克隆可能涉及递归复制对象的所有关联对象,这可能导致性能开销较大。在性能敏感的情况下,需要权衡是否使用原型模式。
总的来说,原型模式在需要创建相似对象且效率要求较高的场景下非常有用。然而,在使用时需要注意克隆的方式、构造函数、对象关系等细节,以确保正确性和可维护性。

相关文章:
【设计模式--原型模式(Prototype Pattern)
一、什么是原型模式 原型模式(Prototype Pattern)是一种创建型设计模式,它的主要目的是通过复制现有对象来创建新的对象,而无需显式地使用构造函数或工厂方法。这种模式允许我们创建一个可定制的原型对象,然后通过复制…...
初识 Redis
初识 Redis 1 认识NoSQL1.1 结构化与非结构化1.2 关联和非关联1.3 查询方式1.4. 事务1.5 总结 2 Redis 概述2.1 应用场景2.2 特性 3 Resis 全局命令4 Redis 基本数据类型4.1 String4.1.1 常用命令4.1.2 命令的时间复杂度4.1.3 使用场景 4.2 Hash4.2.1 常用命令4.2.2 命令的时间…...
php灵异事件,啥都没干数据变了?
这篇文章也可以在我的博客查看 搞WordPress,难免跟php打交道 然而这弱类型语言实在坑有点多 这不今儿又踩了个大坑直接时间-1😅 问题 话不多说直接上代码 <?php $items [1,2];foreach ($items as &$item) {/*empty loop*/} print_r($items)…...
【ffmpeg】基于需要使用videocapture的opencv编译配置(C++)
目录 配置简介ffmpeg源码编译方法记录gstreamer命令行安装方法opencv的编译项记录 配置简介 opencv使用videocapture读取视频流时,需要借助底层的ffmpeg库。如果不能正确编译,会报错,现记录正确编译配置方法。 ffmpeg源码编译方法记录 ope…...
Redisson分布式锁 原理源码 分析
# 基于setnx实现的分布式锁存在的问题: # 为了解决上面的问题,可以用Redisson # Redisson入门 # Redisson可重入锁原理 获取锁的Lua脚本: 释放锁的Lua脚本: # 锁重试原理分析 tryLock()底层代码分析 tim…...
Cocos独立游戏开发框架中的事件管理器
引言 本系列是《8年主程手把手打造Cocos独立游戏开发框架》,欢迎大家关注分享收藏订阅。在独立游戏开发中,事件管理器是一个不可或缺的组件。它为开发者提供了一种灵活的方式来处理游戏内部各种状态变化和用户交互,实现模块之间的解耦和通信…...
keepalived+haproxy 搭建高可用高负载高性能rabbitmq集群
一、环境准备 1. 我这里准备了三台centos7 虚拟机 主机名主机地址软件node-01192.168.157.133rabbitmq、erlang、haproxy、keepalivednode-02192.168.157.134rabbitmq、erlang、haproxy、keepalivednode-03192.168.157.135rabbitmq、erlang 2. 关闭三台机器的防火墙 # 关闭…...
网络安全(黑客)零基础自学
网络安全是什么? 网络安全,顾名思义,网络上的信息安全。 随着信息技术的飞速发展和网络边界的逐渐模糊,关键信息基础设施、重要数据和个人隐私都面临新的威胁和风险。 网络安全工程师要做的,就是保护网络上的信息安…...
如何把本地项目上传github
一、在gitHub上创建新项目 【1】点击添加()-->New repository 【2】填写新项目的配置项 Repository name:项目名称 Description :项目的描述 Choose a license:license 【3】点击确定,项目已在githu…...
跳跃游戏【贪心算法】
跳跃游戏 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。在这里插入图片…...
vue2+element-ui 实现下拉框滚动加载
一、自定义滚动指令。 VUE.directive( el-select-loadmore: { bind(el, binding) { const SELECTWRAP_DOM el.querySelector(.el-select-dropdown .el-select-dropdown__wrap) SELECTWRAP_DOM.addEventListener(scroll, function () { /*…...
探索AIGC人工智能(Midjourney篇)(二)
文章目录 利用Midjourney进行LOGO设计 用ChatGPT和Midjourney的AI绘画,制作儿童绘本故事 探索Midjourney换脸艺术 添加InsightFaceSwap机器人 Midjourney打造专属动漫头像 ChatGPT Midjourney画一幅水墨画 Midjourney包装设计之美 Midjourney24节气海报插画…...
01-Flask-简介及环境准备
Flask-简介及环境准备 前言简介特点Flask 与 Django 的比较环境准备 前言 本篇来介绍下Python的web框架–Flask。 简介 Flask 是一个轻量级的 Web 框架,使用 Python 语言编写,较其他同类型框架更为灵活、轻便且容易上手,小型团队在短时间内…...
【Git游戏】远程分支
origin/<branch> 远程分支在本地以 origin/<branch>格式存在,他指向上次和远程分支通过时的记录 git checkout origin/<branch> 会出现HEAD分离的情况 与远程通讯 git fetch —— 从远端获取数据(实际上将本地仓库中的远程分支更新…...
Day07-ElementUI
Day02-ElementUI 一 菜单设计 1 静态菜单 a 在components文件夹中新建一个组件Menu.vue <template><div class="menu-wrap"><el-menuclass="el-menu-vertical-demo"background-color="#031627"text-color="#fff"ac…...
【Go 基础篇】Go语言中的defer和recover:优雅处理错误
Go语言以其简洁、高效和强大的特性受到了开发者的热烈欢迎。在错误处理方面,Go语言提供了一种优雅的机制,即通过defer和recover组合来处理恐慌(panic)错误。本文将详细介绍Go语言中的defer和recover机制,探讨其工作原理…...
4.15 TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗?
目录 HTTP 的 Keep-Alive TCP 的 Keepalive 总结: HTTP的Keep-Alive,是应用层(用户态)实现的,称为HTTP长连接; TCP的Keepalive,是由TCP层(内核态)实现的,…...
如何在VSCode中将html文件打开到浏览器
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
2022年03月 C/C++(四级)真题解析#中国电子学会#全国青少年软件编程等级考试
第1题:拦截导弹 某国为了防御敌国的导弹袭击, 发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷: 虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。 某天, 雷达捕捉到敌国的…...
五公里场地训练笔记(完整版)
由于考研和口罩等原因,停跑了比较长的时间。中长距离就是这样,修为尽失,大概是要从头开始了,不过还是要乐观的面对,CHEER UP! 翻看咕咚软件,以前的PB是21:12,在2017年9月…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
