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 …...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
