创建型设计模式 - 建造者设计模式 - JAVA

建造者设计模式

    • 一. 简介
    • 二. 使用场景分析
    • 三. 代码案例
      • 3.1 创建ComputerBuilder 类
      • 3.2 修改子类
      • 3.3 修改工厂
      • 3.4 测试
    • 四. 建造者模式案例

前言
这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。
作者:神的孩子都在歌唱

一. 简介

以下是百度百科 对建造者模式的解释 : 文章地址

建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

  1. 解决问题

    • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

    • 当构造过程必须允许被构造的对象有不同表示时。

  2. 在这样的设计模式中,有以下几个角色:

    • builder:为创建一个产品对象的各个部件指定抽象接口。

    • ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。

    • Director:构造一个使用Builder接口的对象。

    • Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口

img

个人理解:建造者模式就是将一大堆东西抽象出来,然后将这些东西拼接成一个不一样的东西(把这当成组装更好理解)

二. 使用场景分析

温馨提示:以下场景分析是我看了几篇建造者模式的文章,然后以自己的理解去编写代码案例总结下来的结论,如果有理解不对的地方或者可以补充的地方请指出

以下是我工厂模式文章举的例子:

image-20231224211149766

这个工厂 可以通过指定磁盘内存 两个参数 去创建一台电脑computer的对象,可是我想在加上一个是否使用喇叭 isSpeaker 的参数 ,有些电脑需要喇叭,有些不需要,所以这个参数不是必须填的了,可是在之前的工厂中,你想创建一台电脑,你就必须要输入指定的参数才可以,可能有很多人说不需要speaker 就输入null就可以了,可是如果这种类似的参数很多呢,要一个个输入null吗?显然是不行的。并且memory和disk是必须输入的参数,这种参数能否和isSpeaker这种可选的参数区分开,方便管理呢?这时候就需要建造者模式去解决这种问题了。

总结上面我个人思考的观点:建造者模式的引入是为了解决工厂和抽象工厂设计模式在对象包含大量属性时的一些问题。当对象包含大量属性时,工厂和抽象工厂设计模式存在三个主要问题。

  1. 从客户端程序传递到 Factory 类的参数太多,这很容易出错,因为大多数时候,参数的类型是相同的,并且从客户端很难维护参数的顺序。
  2. 有些参数可能是可选的,但在工厂模式中,我们被迫发送所有参数,并且可选参数需要作为 NULL 发送。

我们可以通过提供带有必需参数的构造函数,然后提供不同的 setter 方法来设置可选参数来解决参数过多的问题。这种方法的问题是,代码可读性会非常差,而且很容易引入错误。 构建器模式通过提供一种 逐步构建对象的方法 来解决这些的问题。

三. 代码案例

看这个案例前可以先去看看我的写的这篇工厂模式文章,我是根据里面的案例进行优化的

当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,比如以下代码,创建一台没有喇叭 的pc电脑,就要在后面输入null,而且这个参数是必须要输入的

        Computer pc = ComputerFactory.getComputer("pc", "17 GB", "1 TB",null);

可以通过建造者模式优化以上问题,我设计了如下示意图:

image-20240226230811065

让我们看看如何在 这个案例 中实现建造者设计模式解决问题。

3.1 创建ComputerBuilder 类

这个类是通过建造者模式去设计的,我们可以通过这个类去构造computer对象

/*** 电脑对象** @author chenyunzhi* @date 2024/2/25 21:49*/
public class ComputerBuilder extends Computer{private final String memory;private final String disk;private final Boolean isSpeaker;/*** 私有构造函数 以 Builder 类作为参数*/private ComputerBuilder(Builder builder) {this.memory = builder.memory;this.disk = builder.disk;this.isSpeaker = builder.isSpeaker;}public static class Builder {private final String memory;private final String disk;private Boolean isSpeaker;public Builder(String memory, String disk) {this.memory = memory;this.disk = disk;}public Builder setIsSpeaker(Boolean isSpeaker) {this.isSpeaker = isSpeaker;return this;}/*** 返回客户端程序所需的对象*/public Computer build() {return new ComputerBuilder(this);}}@Overridepublic String memory() {return this.memory;}@Overridepublic String disk() {return this.disk;}@Overridepublic Boolean isSpeaker() {return this.isSpeaker;}
}

代码解析:

  1. 首先,我们需要创建一个 ComputerBuilder 类 ,里面有Computer 的所有参数,然后在 ComputerBuilder 类 中创建一个 静态嵌套类 Builder ,然后将所有参数从外部类复制到 Builder 类

  2. 在 Builder 类中创建一个 公共的 构造函数,并将所有必需的属性作为参数。

  3. 在Builder 类 中 设置可选参数 isSpeaker 的方法,并且在设置可选属性后应该返回相同的 Builder 对象。

  4. 最后一步是在 Builder 类中提供一个build()方法,该方法将返回客户端程序所需的对象。为此,我们需要在类中有一个私有构造函数,并以 Builder 类作为参数。

3.2 修改子类

之前我们是通过传入指定参数方式,现在修改成 传入Computer 对象

public class Laptop extends Computer {private final String memory;private final  String disk;private  Boolean isSpeaker;public Laptop(Computer computer) {this.memory = computer.memory();this.disk = computer.disk();this.isSpeaker = computer.isSpeaker();}@Overridepublic String memory() {return this.memory;}@Overridepublic String disk() {return this.disk;}@Overridepublic Boolean isSpeaker() {return this.isSpeaker;}
}

pc

public class Pc extends Computer {private final String memory;private final String disk;private Boolean isSpeaker;public Pc(Computer computer) {this.memory = computer.memory();this.disk = computer.disk();this.isSpeaker = computer.isSpeaker();}@Overridepublic String memory() {return this.memory;}@Overridepublic String disk() {return this.disk;}@Overridepublic Boolean isSpeaker() {return this.isSpeaker;}
}

3.3 修改工厂

ComputerFactory

    public static Computer getComputer(String type, Computer computer) {if (PC.equals(type)) {return new Laptop(computer);} else if (LAPTOP.equals(type)) {return new Pc(computer);} else {return null;}}

3.4 测试

public class Test
{public static void main(String[] args) {Computer laptop = ComputerFactory.getComputer("laptop",new ComputerBuilder.Builder("17 GB", "1TB").setIsSpeaker(true).build());Computer pc = ComputerFactory.getComputer("pc",new ComputerBuilder.Builder("17 GB", "1TB").build());System.out.println("pc电脑 = " + pc);System.out.printf("laptop电脑 = " + laptop);}
}

image-20240226234638623

四. 建造者模式案例

Java 类中的一些构建器模式示例是:

  • java.lang.StringBuilder#append()(不同步)
  • java.lang.StringBuffer#append() (同步)

通过调用append方法,我们可以逐步构建字符串,最终通过toString方法获得最终的表示。

这就是 java 中构建器设计模式的全部内容。

作者:神的孩子都在歌唱
本人博客:https://blog.csdn.net/weixin_46654114
转载说明:务必注明来源,附带本人博客连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/707842.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索 SPA 与 MPA:前端架构的选择与权衡

查看本专栏目录 关于作者 还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas&#x…

Python 实现 OSC 指标计算 (变动速率线):股票技术分析的利器系列(14)

Python 实现 OSC 指标计算 (变动速率线):股票技术分析的利器系列(14) 介绍算法公式 代码rolling函数介绍核心代码计算OSC 完整代码 介绍 OSC(变动速率线)是一种技术指标,通过计算价格的变动速率…

git submodule 模块化管理

Git Submodule 是 Git 版本控制系统中的一项功能,它允许你将一个 Git 仓库嵌套在另一个仓库中。通过使用 Submodule,你可以在一个仓库中引入其他仓库的特定版本,同时保留这些子模块的独立性。 1、添加并初始化 Submodule a、添加 Submodule…

飞行员还是电话接线员?软件开发人员消亡的预测是荒谬的

Stability AI 首席执行官 Emad Mostaque最近因其大胆的预测“五年内将不再有程序员”而成为头条新闻。虽然此类声明在社交媒体上很受欢迎,但它们并不能准确反映创造力在复杂软件开发中的作用的现实。是的,人工智能将深刻改变软件工程行业,但这…

Spring的定时任务不生效、不触发,一些可能的原因,和具体的解决方法。

1 . 未在启动类上加 EnableScheduling 注解 原因:未在Spring Boot应用主类上添加EnableScheduling注解或未在XML配置文件中配置定时任务的启用。解决方法:确保在应用的配置类上添加EnableScheduling注解,启用定时任务。 2 . cron 表达式书写…

R语言使用dietaryindex包计算NHANES数据多种健康饮食指数 (HEI等)(1)

健康饮食指数 (HEI) 是评估一组食物是否符合美国人膳食指南 (DGA) 的指标。Dietindex包提供用户友好的简化方法,将饮食摄入数据标准化为基于指数的饮食模式,从而能够评估流行病学和临床研究中对这些模式的遵守情况,从而促进精准营养。 该软件…

自动从金蝶取数,做BI报表的工具,快来长见识!

技术越进步,分析工具越智能,如今做数据分析、数据可视化,不仅能连接金蝶系统,更能直接从金蝶ERP中取数做分析,自动输出BI数据可视化分析报表。这就是奥威-金蝶BI方案。 是骡子是马,牵出来遛遛就知道&#…

Redis与数据库如何同步?

使用数据库的触发器(Triggers):在数据库中设置触发器,当数据库中的数据发生变化时,触发器将通知Redis更新对应的数据。这通常需要在数据库中编写自定义逻辑以处理触发事件,并确保同步的正确性。 缺点&#…

【C++】拿下! C++中的内存管理

内存管理 1 C 的内存分布2 C语言的内存管理3 C的内存管理3.1 内置类型操作3.2 自定义类型操作 4 operator new与operator delete函数(重点)5 new和delete的实现原理5.1 内置类型5.2 自定义类型new的原理delete的原理new T[ N ] 的原理lete[]的原理 6 总结…

day02_前后端环境搭建(前端工程搭建,登录功能说明,后端项目搭建)

文章目录 1. 软件开发介绍1.1 软件开发流程1.2 角色分工1.3 软件环境1.4 系统的分类 2. 尚品甄选项目介绍2.1 电商基本概念2.1.1 电商简介2.1.2 电商模式B2BB2CB2B2CC2BC2CO2O 2.2 业务功能介绍2.3 系统架构介绍2.4 前后端分离开发 3. 前端工程搭建3.1 Element-Admin简介3.2 El…

idea打包报错,clean、package报错

一、idea在打包时,点击clean或package报错如下: Error running ie [clean]: No valid Maven installation found. Either set the home directory in the configuration dialog or set the M2_HOME environment variable on your system. 示例图&#xf…

深入理解分库、分表、分库分表

前言 分库分表,是企业里面比较常见的针对高并发、数据量大的场景下的一种技术优化方案,所谓"分库分表",根本就不是一件事儿,而是三件事儿,他们要解决的问题也都不一样,这三个事儿分别是"只…

C语言:字符函数 字符串函数 内存函数

C语言:字符函数 & 字符串函数 & 内存函数 字符函数字符分类函数字符转换函数tolowertoupper 字符串函数strlenstrcpystrcatstrcmpstrstrstrtok 内存函数memcpymemmovememsetmemcmp 字符函数 顾名思义,字符函数就是作用于字符的函数,…

uniapp中获取位置信息处理

在微信小程序中,获取定位,是需要用户授权的,那么当用户拒绝授权后,需要重新获取定位时,是不会再调起授权界面,这时需要用户主动打开设置界面,才可以重新开启授权权限; 那么&#xf…

【MySQL | 第一篇】undo log、redo log、bin log三者之间的区分?

undo log、redo log、bin log三者之间的区分? 从 产生的时间点、日志内容、用途 三方面展开论述即可 1.undo log——撤销日志 时间点:事务开始之前产生,根据当前版本的数据生成一个undo log,也保存在事务开始之前 作用&#xf…

PHP学习笔记2——前后端,mysql增删改查

php是一种适用于后端与前端的编程语言 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>index</t…

【亚马逊云新春特辑②】构生成式 AI 文生图工具之借助ControlNet进行AI绘画创作【生成艺术二维码】

文章目录 1.1 生成艺术二维码1&#xff09;制作基础二维码2&#xff09;确定艺术风格3&#xff09;生成艺术二维码4&#xff09;结果优化 AIGC 的可控性是它进入实际生产最关键的一环。在此之前&#xff0c;许多用户希望 AI 生成的结果尽可能符合要求&#xff0c;但都不尽如人意…

961. 最大获利(网络流,最小割,最大权闭合图)

活动 - AcWing 新的技术正冲击着手机通讯市场&#xff0c;对于各大运营商来说&#xff0c;这既是机遇&#xff0c;更是挑战。 THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜&#xff0c;需要做太多的准备工作&#xff0c;仅就站址选择一项&#xff0c;就需要完…

linux centos7.9改dns和ip

vi /etc/sysconfig/network-scripts/ifcfg-ens32 &#xff1a;wq后 重启网络服务 systemctl restart network —————————————————————————— 篇外话题 软件下载 xshell可以从腾讯软件中心下载

基于Rust语言,和WebAssembly技术,与JavaScript结合,的具体应用场景

基于Rust语言与WebAssembly&#xff08;Wasm&#xff09;技术并与JavaScript结合&#xff0c;可以应用于多个场景&#xff0c;特别是在需要高性能和/或低级系统访问的情况下。下面是一些具体的应用场景&#xff1a; 性能密集型任务: Rust加上Wasm适合执行计算密集型任务&#x…