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

23种设计模式-原型(Prototype)设计模式

文章目录

  • 一.什么是原型设计模式?
  • 二.原型模式的特点
  • 三.原型模式的结构
  • 四.原型模式的优缺点
  • 五.原型模式的 C++ 实现
  • 六.原型模式的 Java 实现
  • 七. 代码解析
  • 八.总结

类图: 原型设计模式类图

一.什么是原型设计模式?

原型模式(Prototype Pattern) 是一种创建型设计模式,它通过复制现有对象来生成新对象,而不是通过实例化类来创建。这种模式基于对象的克隆机制,适用于需要频繁创建对象的场景,可以提高性能并减少复杂的初始化过程。

二.原型模式的特点

  • 克隆对象:通过复制已有对象生成新对象,而非通过构造函数创建。
  • 性能优化:避免复杂对象创建的高开销。
  • 灵活性:可以动态添加或删除原型,而不影响其他对象。

三.原型模式的结构

  • Prototype(抽象原型类):定义了克隆方法,通常是 clone() 方法。
  • ConcretePrototype(具体原型类):实现抽象原型类的克隆方法。
  • Client(客户端):调用克隆方法创建新对象,而无需关心对象的具体类型。
    原型设计模式类图

四.原型模式的优缺点

  • 优点:
    • 性能优势:克隆比重新创建对象效率更高。
    • 动态性:无需编译时依赖类,可以在运行时动态生成对象。
    • 避免依赖性:通过克隆机制,可以避免直接依赖类的构造函数。
  • 缺点:
    • 复杂性增加:需要正确实现克隆方法,尤其是深拷贝场景。
    • 资源消耗:可能会为每个可克隆的对象维护克隆逻辑,导致类职责增多。

五.原型模式的 C++ 实现

#include <iostream>
#include <string>
#include <memory> // for smart pointers
using namespace std;// 抽象原型类
class Prototype {
public:virtual ~Prototype() = default;// 克隆方法(纯虚函数)virtual unique_ptr<Prototype> clone() const = 0;virtual void display() const = 0;
};// 具体原型类1
class ConcretePrototypeA : public Prototype {
private:string data; // 模拟一些状态
public:ConcretePrototypeA(string data) : data(data) {}// 克隆方法unique_ptr<Prototype> clone() const override {return make_unique<ConcretePrototypeA>(*this); // 调用拷贝构造函数}void display() const override {cout << "ConcretePrototypeA with data: " << data << endl;}
};// 具体原型类2
class ConcretePrototypeB : public Prototype {
private:int value; // 模拟一些状态
public:ConcretePrototypeB(int value) : value(value) {}// 克隆方法unique_ptr<Prototype> clone() const override {return make_unique<ConcretePrototypeB>(*this); // 调用拷贝构造函数}void display() const override {cout << "ConcretePrototypeB with value: " << value << endl;}
};// 客户端代码
void ClientCode(const Prototype& prototype) {auto clonedObject = prototype.clone(); // 克隆一个对象clonedObject->display();               // 显示克隆对象的内容
}int main() {// 创建原型对象ConcretePrototypeA prototypeA("PrototypeA Data");ConcretePrototypeB prototypeB(42);cout << "Cloning ConcretePrototypeA:" << endl;ClientCode(prototypeA);cout << "\nCloning ConcretePrototypeB:" << endl;ClientCode(prototypeB);return 0;
}

六.原型模式的 Java 实现

// 抽象原型类
abstract class Prototype implements Cloneable {public abstract Prototype clone();public abstract void display();
}// 具体原型类A
class ConcretePrototypeA extends Prototype {private String data;public ConcretePrototypeA(String data) {this.data = data;}@Overridepublic Prototype clone() {try {return (Prototype) super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone not supported!");}}@Overridepublic void display() {System.out.println("ConcretePrototypeA with data: " + data);}
}// 具体原型类B
class ConcretePrototypeB extends Prototype {private int value;public ConcretePrototypeB(int value) {this.value = value;}@Overridepublic Prototype clone() {try {return (Prototype) super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone not supported!");}}@Overridepublic void display() {System.out.println("ConcretePrototypeB with value: " + value);}
}// 客户端代码
public class PrototypePatternExample {public static void main(String[] args) {// 创建原型对象ConcretePrototypeA prototypeA = new ConcretePrototypeA("PrototypeA Data");ConcretePrototypeB prototypeB = new ConcretePrototypeB(42);System.out.println("Cloning ConcretePrototypeA:");Prototype clonedA = prototypeA.clone();clonedA.display();System.out.println("\nCloning ConcretePrototypeB:");Prototype clonedB = prototypeB.clone();clonedB.display();}
}

七. 代码解析

  • 抽象原型类(Prototype)
    • 定义了一个 clone() 方法,用于生成当前对象的副本。
    • 使用虚函数,使得派生类可以实现自己的克隆逻辑。
  • 具体原型类(ConcretePrototypeA 和 ConcretePrototypeB)
    • 实现了 clone() 方法,通过调用自身的拷贝构造函数完成对象的克隆。
    • ConcretePrototypeA 和 ConcretePrototypeB 模拟了不同的数据成员,演示了克隆不同类型对象的效果。
  • 客户端代码
    • 接收一个 Prototype 对象的引用,并通过调用 clone() 方法克隆出一个新对象。
    • 客户端无需关心具体的类,只需通过 Prototype 接口调用克隆方法即可。

八.总结

 原型模式通过克隆的方式创建新对象,而不依赖于类的构造函数。这种模式在需要频繁创建对象、或者需要动态生成对象的场景中非常有用。通过正确实现 clone() 方法,可以有效提高程序的灵活性和性能。然而,在实现复杂对象的深拷贝时,需要特别注意对象之间的依赖关系和资源管理,以避免潜在的错误。
应用场景:

  • 复杂对象的创建:初始化需要耗费大量资源的对象可以通过克隆来生成新对象。
  • 性能优化:避免使用构造函数或工厂方法重复创建对象。
  • 动态对象管理:需要动态生成对象而不依赖具体类。

相关文章:

23种设计模式-原型(Prototype)设计模式

文章目录 一.什么是原型设计模式&#xff1f;二.原型模式的特点三.原型模式的结构四.原型模式的优缺点五.原型模式的 C 实现六.原型模式的 Java 实现七. 代码解析八.总结 类图&#xff1a; 原型设计模式类图 一.什么是原型设计模式&#xff1f; 原型模式&#xff08;Prototype…...

Qt—QLineEdit 使用总结

文章参考:Qt—QLineEdit 使用总结 一、简述 QLineEdit是一个单行文本编辑控件。 使用者可以通过很多函数,输入和编辑单行文本,比如撤销、恢复、剪切、粘贴以及拖放等。 通过改变 QLineEdit 的 echoMode() ,可以设置其属性,比如以密码的形式输入。 文本的长度可以由 m…...

go-zero使用自定义模板实现统一格式的 body 响应

前提 go环境的配置、goctl的安装、go-zero的基本使用默认都会 需求 go-zero框架中&#xff0c;默认使用goctl命令生成的代码并没有统一响应格式&#xff0c;现在使用自定义模板实现统一响应格式&#xff1a; {"code": 0,"msg": "OK","d…...

BUGKU printf

整体思路 实现循环-->获取libc版本和system函数地址->将strcpy的got表项修改为system并获得shell 第一步&#xff1a;实现循环 从汇编语句可以看出&#xff0c;在每次循环结束时若0x201700处的值是否大于1则会继续循环。 encode1会将编码后的结果保存至0x2015c0处&am…...

深度学习:梯度下降法

损失函数 L&#xff1a;衡量单一训练样例的效果。 成本函数 J&#xff1a;用于衡量 w 和 b 的效果。 如何使用梯度下降法来训练或学习训练集上的参数w和b &#xff1f; 成本函数J是参数w和b的函数&#xff0c;它被定义为平均值&#xff1b; 损失函数L可以衡量你的算法效果&a…...

`console.log`调试完全指南

大家好&#xff0c;这里是 Geek技术前线。 今天我们来探讨 Console.log() 的一些优点。并分析一些基本概念和实践&#xff0c;这些可以让我们的调试工作变得更加高效。 理解前端 log 与后端 log 的区别 前端 log 与后端 log 有着显著的不同&#xff0c;理解这一点至关重要。…...

ROS VSCode调试方法

VSCode 调试 Ros文档 1.编译参数设置 cd catkin_ws catkin_make -DCMAKE_BUILD_TYPEDebug2.vscode 调试插件安装 可在扩展中安装(Ctrl Shift X): 1.ROS 2.C/C 3.C Intelliense 4.Msg Language Support 5.Txt Syntax 3.导入已有或者新建ROS工作空间 3.1 导入工作…...

16 —— Webpack多页面打包

需求&#xff1a;把 黑马头条登陆页面-内容页面 一起引入打包使用 步骤&#xff1a; 准备源码&#xff08;html、css、js&#xff09;放入相应位置&#xff0c;并改用模块化语法导出 原始content.html代码 <!DOCTYPE html> <html lang"en"><head&…...

微服务即时通讯系统的实现(服务端)----(3)

目录 1. 消息存储子服务的实现1.1 功能设计1.2 模块划分1.3 模块功能示意图1.4 数据管理1.4.1 数据库消息管理1.4.2 ES文本消息管理 1.5 接口的实现1.5.1 消息存储子服务所用到的protobuf接口实现1.5.2 最近N条消息获取接口实现1.5.3 指定时间段消息搜索接口实现1.5.4 关键字消…...

.net6.0 mvc 传递 model 实体参数(无法对 null 引用执行运行时绑定)

说一下情况&#xff1a; 代码没问题&#xff0c;能成功从数据库里查到数据&#xff0c;能将数据丢给ViewBag.XXXX, 在View页面也能获取到 ViewBag.XXXX的值&#xff0c;但是发布到线上后报这个错&#xff1a; Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 无法对 …...

VUE 入门级教程:开启 Vue.js 编程之旅

一、Vue.js 简介 Vue.js 是一套构建用户界面的渐进式 JavaScript 框架。它专注于视图层的开发&#xff0c;能够轻松地与其他库或现有项目进行整合。Vue.js 的核心库只关注视图层&#xff0c;通过简洁的 API 实现数据绑定和 DOM 操作的响应式更新&#xff0c;让开发者可以高效地…...

Ubantu系统docker运行成功拉取失败【成功解决】

解决docker运行成功拉取失败 失败报错 skysky-Legion-Y7000-IRX9:~$ docker run hello-world docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head “http://%2Fvar%2Frun%2Fdocker.sock/_ping”: dial uni…...

mvn-mac操作小记

1.安装brew 如果报错&#xff0c;Warning: /opt/homebrew/bin is not in your PATH. vim ~/.zshrc&#xff0c;最后一行追加 export PATH“/opt/homebrew/bin:$PATH” source ~/.zshrc 2.安装brew install maven mvn -version查看路径 Maven home: /opt/homebrew/Cellar/mav…...

机器学习——生成对抗网络(GANs):原理、进展与应用前景分析

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一. 生成对抗网络的基本原理二. 使用步骤2.1 对抗性训练2.2 损失函数 三. GAN的变种和进展四. 生成对抗网络的应用五. 持续挑战与未来发展方向六. 小结 前言 生…...

「Mac畅玩鸿蒙与硬件33」UI互动应用篇10 - 数字猜谜游戏

本篇将带你实现一个简单的数字猜谜游戏。用户输入一个数字&#xff0c;应用会判断是否接近目标数字&#xff0c;并提供提示“高一点”或“低一点”&#xff0c;直到用户猜中目标数字。这个小游戏结合状态管理和用户交互&#xff0c;是一个入门级的互动应用示例。 关键词 UI互…...

Ps:存储 Adobe PDF

在 Adobe Photoshop 中&#xff0c;将图像保存为 PDF 文件时&#xff0c; 会弹出“存储 Adobe PDF” Save Adobe PDF对话框。在此对话框中提供了多个选项&#xff0c;用于控制 PDF 文件的输出&#xff0c;包括一般设置&#xff08;选择预设、兼容性和保留编辑功能&#xff09;、…...

DDR3保姆级使用教程:ZYNQ 7010

内容:使用DDR3 IP核&#xff0c;向DDR3写入数据&#xff0c;然后再读出数据&#xff0c;通过串口打印。 设备&#xff1a;ZYNQ 7010 xc7z010clg-400-1。软件VIVADO 2018.3 &#xff08;1&#xff09;工程模块&#xff1a;一个写FIFO&#xff0c;一个读FIFO。一个ZYNQ IP核&am…...

OpenCV 模板匹配全解析:从单模板到多模板的实战指南

简介&#xff1a;本文深入探讨 OpenCV 中的模板匹配技术。详细介绍构建输入图像与模板图像的步骤&#xff0c;包括读取、截取、滤波与存储等操作。剖析 cv2.matchTemplate 语法及其参数含义&#xff0c;阐述不同匹配方法下结果值的意义。同时讲解 cv2.minMaxLoc 语法&#xff0…...

【JAVA] 杂谈: java中的拷贝(克隆方法)

这篇文章我们来介绍什么是拷贝&#xff0c;并且实现浅拷贝到深拷贝。 目录 一、浅拷贝 1.1 clone 方法 1.2 实现浅拷贝&#xff1a; 1.2.1 重写 clone方法 1.2.2 实现接口 Cloneable 1.2.3 调用克隆方法 1.2.4 原理图&#xff1a;​ 1.3 浅拷贝的不足 1.3.1 增加引用…...

使用 PDF API 合并 PDF 文件

内容来源&#xff1a; 如何在 Mac 上合并 PDF 文件 1. 注册与认证 您可以注册一个免费的 ComPDFKit API 帐户&#xff0c;该帐户允许您在 30 天内免费无限制地处理 1,000 多个文档。 ComPDFKit API 使用 JSON Web Tokens 方法进行安全身份验证。从控制面板获取您的公钥和密钥&…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...