3.创建型设计模式详解:生成器模式与原型模式的深度解析
设计模式(Design Patterns)是软件开发中常用的解决方案,帮助开发者处理常见的设计问题。创建型设计模式专注于对象的实例化,旨在提高系统的灵活性和可维护性。在这篇文章中,我们将深入探讨创建型设计模式中的生成器模式(Builder Pattern)和原型模式(Prototype Pattern),详细分析它们的应用场景、优缺点,并通过类图和综合案例加以对比。
1. 创建型设计模式概述
创建型设计模式包括以下几种常见模式:
- 单例模式(Singleton Pattern) 设计模式入门系列
- 工厂模式(Factory Patterns) 设计模式入门系列
- 简单工厂(Simple Factory)
- 工厂方法(Factory Method)
- 抽象工厂(Abstract Factory)
- 生成器模式(Builder Pattern)
- 原型模式(Prototype Pattern)
生成器模式和原型模式分别解决了对象创建过程中的复杂性和灵活性问题。接下来我们将重点讨论这两种模式。
2. 生成器模式(Builder Pattern)
2.1. 概述
生成器模式用于构建复杂对象,将对象的构建过程与其表示分离。通过使用生成器模式,用户可以一步一步地构建一个对象,而不必担心创建的顺序和复杂性。
2.2. 结构与实现
生成器模式通常包括以下几个关键角色:
- Builder: 定义构建产品各个部分的抽象接口。
- ConcreteBuilder: 实现Builder接口,构建并装配各个部分。
- Product: 表示被构建的复杂对象。
- Director: 指挥构建过程,使用Builder接口来构造复杂对象。
2.3. 优缺点
优点:
- 控制复杂构建过程: 提供了构建对象的详细步骤,能够精确控制对象的构建过程。
- 易于扩展: 可以通过不同的ConcreteBuilder类创建不同的对象表示。
缺点:
- 增加复杂性: 对于简单对象,生成器模式可能显得过于复杂。
- 依赖于Director: 需要额外的Director类来管理构建流程。
2.4. 应用场景
生成器模式适用于以下场景:
- 需要构建复杂对象,且该对象由多个部分组成。
- 构建过程需要按步骤进行,且各步骤有可能变化。
- 希望将对象的创建与表示分离,以支持多个表示。
3. 原型模式(Prototype Pattern)
3.1. 概述
原型模式通过复制现有对象来创建新对象,而不是通过实例化。该模式适用于需要创建大量相似对象的场景。
3.2. 结构与实现
原型模式的关键角色包括:
- Prototype: 声明一个克隆自身的接口。
- ConcretePrototype: 实现克隆接口,执行对象的浅拷贝或深拷贝。
- Client: 通过调用克隆方法来创建新的对象。
3.3. 优缺点
优点:
- 提高性能: 克隆对象比直接实例化对象更加高效,尤其是在创建复杂对象时。
- 简化对象创建: 通过克隆现有对象,可以避免使用构造函数创建对象的复杂性。
缺点:
- 深拷贝复杂: 深拷贝可能需要手动实现,并且复杂度较高。
- 潜在问题: 如果原型对象存在循环引用,克隆可能会引发问题。
3.4. 应用场景
原型模式适用于以下场景:
- 需要创建大量相似对象,并且实例化过程代价较高。
- 希望避免重复创建对象,并提高性能。
- 需要保存对象的状态,并在稍后恢复这些状态。
4. 生成器模式与原型模式对比
4.1. 区别
比较维度 | 生成器模式 | 原型模式 |
---|---|---|
目标 | 分步骤构建复杂对象 | 通过克隆现有对象创建新对象 |
实现方式 | 将对象的构建过程封装在Builder和Director中 | 使用原型实例的克隆方法创建对象 |
使用场景 | 复杂对象构建 | 创建大量相似对象,避免复杂构造过程 |
优点 | 控制构建过程,支持多种表示 | 性能高效,简化对象创建 |
缺点 | 增加复杂性,依赖Director | 深拷贝复杂,可能引发克隆问题 |
4.2. 类图对比
生成器模式类图:
+---------------+| Director |+---------------+|v+---------------+| Builder |<---------------------++---------------+ || |+---------------+ +-----------------------------+| ConcreteBuilder|<------| ConcreteProduct |+---------------+ +-----------------------------+| |v v+-----------------------------+ +-----------------------------+| Product | | Product |+-----------------------------+ +-----------------------------+
原型模式类图:
+---------------+| Prototype |+---------------+|v+---------------------+| ConcretePrototype |+---------------------+|v+---------------------+| ClonedObject |+---------------------+
4.3. 案例对比
生成器模式案例:
假设我们在开发一个在线商店,需要构建不同类型的订单。每个订单包含客户信息、商品列表、付款方式、配送地址等。使用生成器模式,我们可以将构建过程分解成多个步骤,并根据需求选择不同的构建器来创建不同类型的订单。
原型模式案例:
如果我们需要为在线商店创建大量相似订单,例如为一个特定客户创建多个相同的订单,可以通过原型模式克隆一个现有订单,而不是重复构建新订单。这种方式可以大大提高效率,并减少冗余代码。
下面是一个简单的Java案例,展示了生成器模式和原型模式的使用。案例使用了订单管理的场景,分别展示如何用生成器模式构建复杂订单,以及如何用原型模式克隆订单。
1. 生成器模式案例
// 产品类:Order(订单)
public class Order {private String customerName;private String product;private int quantity;private String address;// 私有构造函数,确保只能通过生成器创建订单private Order(OrderBuilder builder) {this.customerName = builder.customerName;this.product = builder.product;this.quantity = builder.quantity;this.address = builder.address;}// 静态内部类:OrderBuilder(订单生成器)public static class OrderBuilder {private String customerName;private String product;private int quantity;private String address;public OrderBuilder setCustomerName(String customerName) {this.customerName = customerName;return this;}public OrderBuilder setProduct(String product) {this.product = product;return this;}public OrderBuilder setQuantity(int quantity) {this.quantity = quantity;return this;}public OrderBuilder setAddress(String address) {this.address = address;return this;}// 构建方法,返回Order实例public Order build() {return new Order(this);}}@Overridepublic String toString() {return "Order{" +"customerName='" + customerName + '\'' +", product='" + product + '\'' +", quantity=" + quantity +", address='" + address + '\'' +'}';}// 测试生成器模式的主方法public static void main(String[] args) {// 使用生成器模式构建一个订单Order order = new Order.OrderBuilder().setCustomerName("张三").setProduct("笔记本电脑").setQuantity(2).setAddress("北京市海淀区").build();System.out.println(order);}
}
2. 原型模式案例
// 产品类:Order(订单),实现Cloneable接口
public class Order implements Cloneable {private String customerName;private String product;private int quantity;private String address;public Order(String customerName, String product, int quantity, String address) {this.customerName = customerName;this.product = product;this.quantity = quantity;this.address = address;}// 克隆方法,实现浅拷贝@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Order{" +"customerName='" + customerName + '\'' +", product='" + product + '\'' +", quantity=" + quantity +", address='" + address + '\'' +'}';}// 测试原型模式的主方法public static void main(String[] args) {try {// 创建一个订单Order originalOrder = new Order("李四", "智能手机", 3, "上海市浦东新区");// 克隆订单Order clonedOrder = (Order) originalOrder.clone();System.out.println("原订单: " + originalOrder);System.out.println("克隆订单: " + clonedOrder);} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}
代码解读
-
生成器模式: 通过
Order.OrderBuilder
构建复杂的订单对象,可以灵活设置订单的各个属性,最终调用build()
方法生成Order
实例。适用于对象的创建过程涉及多个步骤,且每个步骤可能有不同的配置需求。 -
原型模式: 通过实现
Cloneable
接口,并重写clone()
方法,能够快速复制一个订单对象。适用于需要频繁创建相似对象的场景,能够提高创建效率,减少冗余代码。
5. 开发者的建议
-
选择合适的模式: 在实际开发中,根据项目需求和对象的复杂程度,选择合适的设计模式。如果对象创建非常复杂且有多个变种,可以考虑生成器模式;如果对象创建过程非常频繁且需要优化性能,原型模式是不错的选择。
-
结合其他模式使用: 生成器模式和原型模式并不孤立,它们可以结合其他设计模式(如工厂模式)使用,以进一步增强系统的灵活性和可维护性。例如,工厂模式可以与生成器模式结合,来创建复杂的对象。
-
关注对象的深拷贝和浅拷贝: 在使用原型模式时,务必理解并正确实现对象的深拷贝和浅拷贝,避免潜在的克隆问题。
通过本文的分析,我们详细探讨了生成器模式和原型模式的结构、应用场景、优缺点,并通过对比表格和类图来加深理解。无论是在构建复杂对象还是优化对象创建过程,这两种模式都能提供强大的支持。
相关文章:
3.创建型设计模式详解:生成器模式与原型模式的深度解析
设计模式(Design Patterns)是软件开发中常用的解决方案,帮助开发者处理常见的设计问题。创建型设计模式专注于对象的实例化,旨在提高系统的灵活性和可维护性。在这篇文章中,我们将深入探讨创建型设计模式中的生成器模式…...
goframe结构体标签和命令行标签
元数据gmeta 基础标签 更多了解:https://swagger.io/specification/ g.Meta path:"/profile" method:"get" summary:"展示个人资料页面" tags:"个人" g.Meta mime:"text/html" type:"string" example…...

pytest压力测试:不断发送数据,直到发现数据丢失
示例场景 假设有一个 send_data 函数接受数据并返回成功或失败的状态。 创建一个测试用例,通过逐步增加数据量来测试这个函数,直到返回失败为止。 步骤 定义压力测试函数 定义一个函数。不断发送数据,直到发现数据丢失。 创建 pytest 测试…...

自选择问题和处理效应模型
自选择问题和处理效应模型 DGP 注意: 这里的概率密度超过了1,这是正常的。概率密度的三原则,1是大于等于0;2是积分等于1;对于连续型随机变量,给定一个具体的x值,f(x)并不是该事件发生的概率。而…...

[数据集][目标检测]水面垃圾检测数据集VOC+YOLO格式2027张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2027 标注数量(xml文件个数):2027 标注数量(txt文件个数):2027 标注…...

OpenCV 之 模版匹配多个对象、图片旋转 综合应用
引言 在图像处理和计算机视觉中,模板匹配是一种常用的技术,用于在一幅较大的图像中查找与给定模板图像相似的部分。然而,在实际应用中,目标物体可能会出现在不同的角度,这就需要我们在匹配之前对模板进行旋转处理。本…...
ZooKeeper 中的 Curator 框架解析
Apache ZooKeeper 是一个为分布式应用提供一致性服务的软件。它提供了诸如配置管理、分布式同步、组服务等功能。在使用 ZooKeeper 时,Curator 是一个非常流行的客户端库,它简化了 ZooKeeper 的使用,提供了高级的抽象和丰富的工具。本文将详细…...

机械学习—零基础学习日志(Python做数据分析02)
现在开始使用Python尝试做数据分析。具体参考的网址链接放在了文章末尾。 引言 我通过学习《利用Python进行数据分析》这本书来尝试使用Python做数据分析。书里让下载,anaconda,使用Jupyter来写代码,只是下载一个anaconda的确有点费时间&am…...

BRAM IP Native模式使用
简介 BRAM(Block RAM)是FPGA(Field-Programmable Gate Array)中的一种专用RAM资源,固定分布在FPGA内部的特定位置。该内容主要对BRAM(Block RAM”的缩写)Native模式下IP界面做详细描述和使用…...
react的useRef用什么作用
useRef 是 React 提供的一个钩子,用于在函数组件中创建和管理对 DOM 元素或组件实例的引用。它返回一个包含 current 属性的对象,可以用来存储对某个值的引用,而这个引用在组件的整个生命周期内保持不变。 useRef 的主要用途 1.访问 DOM 元素…...

10.2 TCP IP模型、IP协议、IPv4、子网掩码
TCP / IP 协议族 IP协议 IPv4地址 IPv4地址分类 子网掩码 子网掩码用来区分 网络地址 和 主机地址 真题 1...

工业相机飞拍的原理及工作原理
工业相机飞拍(或称为工业高速相机飞行拍摄)是一种利用高速图像捕捉技术和精密运动控制系统进行高效图像采集的先进技术。它广泛应用于工业检测、质量控制和自动化生产等领域。本文将详细探讨工业相机飞拍的原理及其工作方式。 一、工业相机飞拍的基本概…...

通过AI来创建一个_____html css网页制作成品 例子演示
使用AI 输入创建一个 html css网页制作成品 例 然后出来 好的,我将为您创建一个简单的HTML和CSS网页制作的示例。这个示例将包括基本的布局、文本样式和一些内联的CSS样式。 { "name": "dalle", "description": "A simple exa…...

C ++ 从单链表到创建二叉树到二叉树的遍历(结构体)
首先我们要了解二叉树的数据结构是什么,本质上二叉树是一个有两个节点的链表,我们先了解的单链表的相关定义 单链表 创建一个朴素的单链表 #include <iostream>using namespace std;struct Node{int val;Node* next;Node(int x) : val(x), next(…...
Python 编程:如何巧妙运用 `abc` 模块解锁面向对象设计的新维度?
引言 在软件开发的世界里,面向对象编程(OOP)作为一门艺术,其精髓在于通过封装、继承与多态来构建可维护性高、易于扩展的系统。而在 Python 这门语言中,abc 模块则为我们提供了一种优雅的方式来定义抽象基类ÿ…...
Jenkins 执行 shell 时报错 Host key verification failed.
1. 问题描述 在 jenkins 中执行下面的 shell 语句时 sshpass -p "123456" scp -r * dep192.168.1.100:/home/dep/Desktop/报错 Host key verification failed.可能原因是由于首次登录时需要输入 yes 导致无法连接成功。 The authenticity of host 192.168.1.100…...
MyBatis-Plus&Druid数据源
MyBatis-Plus(简称MP)和Druid数据源在Java开发中各自扮演着重要的角色,它们分别增强了MyBatis的数据库操作能力和提供了高效的数据库连接池管理。以下是对MyBatis-Plus和Druid数据源的总结: MyBatis-Plus 定义与特性:…...

MTPA控制分析与推导
目录 MTPA (Maximum torque per ampere) 一. 控制目的 二. 设计思路 三. 推导过程 MTPA (Maximum torque per ampere) 一. 控制目的 忽略电机中的铁耗只考虑铜耗的背景下,希望实现铜耗最小化。 二. 设计思路 通过给出电机在d-q坐标系下的等效电路模型&…...
Spring Boot 的Web项目如何直接显示html
前言 实际的开发中,在Spring Boot的Web项目中直接使用html文件的场景已经比较少了, 或者是只需要很简单的页面显示,或者是演示的需要, 大部分的状况都是Spring Boot作为后端提供REST 的服务,结合其他的一些前端Framework进行开发,比如VUE,Ext JS等。 Spring Boot项目中…...

【回收站选址】
题目 代码 #include <bits/stdc.h> using namespace std; const int R 2e91; typedef long long LL; unordered_set<LL> s; int piles[5]; int dx[4] {-1, 0, 1, 0}, dy[4] {0, 1, 0, -1}; int dx1[4] {-1, -1, 1, 1}, dy1[4] {-1, 1, -1, 1};bool check(LL …...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...