创建型设计模式 - 建造者设计模式 - 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);
        }
    }
    
    @Override
    public String memory() {
        return this.memory;
    }

    @Override
    public String disk() {
        return this.disk;
    }

    @Override
    public 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();
    }
    
    @Override
    public String memory() {
        return this.memory;
    }

    @Override
    public String disk() {
        return this.disk;
    }

    @Override
    public 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();
    }

    @Override
    public String memory() {
        return this.memory;
    }

    @Override
    public String disk() {
        return this.disk;
    }

    @Override
    public 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
转载说明:务必注明来源,附带本人博客连接。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity中的UI系统之GUI

目录 概述工作原理和主要作用基础控件重要参数及文本和按钮多选框和单选框输入框和拖动条图片绘制和框 复合控件工具栏和选择网络滚动视图和分组窗口 自定义整体样式自定义皮肤样式 概述 什么是UI系统 UI是User Interface(用户界面)的简称,用…

Bert基础(五)--解码器(下)

1、 多头注意力层 下图展示了Transformer模型中的编码器和解码器。我们可以看到,每个解码器中的多头注意力层都有两个输入:一个来自带掩码的多头注意力层,另一个是编码器输出的特征值。 让我们用R来表示编码器输出的特征值,用M来…

Unity安装与简单设置

安装网址:https://unity.cn 设置语言: 设置安装位置:否则C盘就会爆了 获取一个个人的资格证: 开始安装: 安装完毕。 添加模块:例如简体中文 新建项目: 布局2*3、单栏布局、 设置…

el-table实现转置表格

vue版本&#xff1a;vue2.6.10 elementui版本&#xff1a;2.15.14 实现效果&#xff1a;el-table实现行列互换 代码&#xff1a; <template><div class"app-container"><span>原始数据</span><el-table:data"datas"border>…

循环结构:for循环,while循环,do-while,死循环

文章目录 for循环for案例&#xff1a;累加for循环在开发中的常见应用场景 whilewhile循环案例&#xff1a; for和while的区别&#xff1a;do-while三种循环的区别小结死循环 快捷键 ctrlaltt for循环 看循环执行多少次&#xff0c;就看有效数字有几个 快捷键 fori 示例代码&am…

Netty01NIO

NIO基础 NIO &#xff1a;non-blocking io 非阻塞 IO 笔记 www.zgtsky.top 网课&#xff1a;黑马Netty 三大组件 Channel & Buffer channel 有一点类似于 stream&#xff0c;它就是读写数据的双向通道&#xff0c;可以从 channel 将数据读入 buffer&#xff0c;也可以…

工作微信统一管理(还带监管功能)

1.会话页面(可统一管理多个微信号、聚合聊天、手动搜索添加好友、通过验证请求、查看好友的朋友圈等) 2.聊天历史(可查看 所有聊天记录&#xff0c;包括手机.上撤回、删除的消息) 3.群发助手(可以一 -次群发多个好友和群&#xff0c;还可以选择定时发送&#xff0c;目前还在内测…

docker (十二)-私有仓库

docker registry 我们可以使用docker push将自己的image推送到docker hub中进行共享&#xff0c;但是在实际工作中&#xff0c;很多公司的代码不能上传到公开的仓库中&#xff0c;因此我们可以创建自己的镜像仓库。 docker 官网提供了一个docker registry的私有仓库项目&#…

微服务之qiankun主项目+子项目搭建

主项目使用history&#xff0c;子项目使用hash模式 1. 下载安装"qiankun": "^2.10.13"2. 手动调用qiankun,使用vue脚手架搭建的项目1. 主项目配置&#xff08;我使用的是手动调用乾坤&#xff0c;在指定页面显示内容&#xff09;1. 要使用的页面中引入乾坤…

蓝桥杯备战刷题three(自用)

1.合法日期 #include <iostream> #include <map> #include <string> using namespace std; int main() {map<string,int>mp;int days[13]{0,31,28,31,30,31,30,31,31,30,31,30,31};for(int i1;i<12;i){for(int j1;j<days[i];j){string sto_strin…

Word | 论文使用 Springer LNICST 工具包进行格式化

目录 Step1&#xff1a;下载 Springer LNICST 工具包 Step2&#xff1a;导入宏文件 Step3&#xff1a;处理导入失败&#xff08;大概意思是这个宏不安全&#xff09; Step4&#xff1a;导入成功并使用 Step1&#xff1a;下载 Springer LNICST 工具包 会议官网的 SUBMISSIO…

合唱队形洛谷

这题的状态转移方程为dp[i]max(dp[i]&#xff0c;dp[j]1) 因而可以有代码 #include<iostream> #include<algorithm> using namespace std; int arr[102][2]; int a[102]; int main() { int n; cin >> n; for (int i 1; i < n; i) { cin >>…

1、docker入门

文章目录 1、tocker简介2、tocker的安装&环境配置2、配置阿里云镜像3、基本命令1、镜像命令2、docker基本命令3、镜像基本命令4、Docker 容器常用命令 1、tocker简介 新一代的虚拟化技术 2、tocker的安装&环境配置 uname -r1、首先查看liunx的内核 yum update -y2、更…

selenium-激活pycharm,以及在pycharm中使用selenium时标红报错问题处理

激活pycharm&#xff1a;http://idea.955code.com/ 01 pycharm中导入selenium报错 现象: pycharm中输入from selenium import webdriver, selenium标红 原因1: pycharm使用的虚拟环境中没有安装selenium&#xff1a; 解决方法: 在pycharm中通过设置或terminal面板重新安装s…

VR元宇宙的概念|VR体验店加盟|虚拟现实设备销售

VR元宇宙是一个结合了虚拟现实&#xff08;Virtual Reality&#xff09;和增强现实&#xff08;Augmented Reality&#xff09;等技术的概念&#xff0c;代表着一个虚拟的多维度世界。它是一个由数字化的空间构成的虚拟环境&#xff0c;可以通过虚拟现实设备进行交互和探索。 元…

本届挑战赛季军方案:基于图网络及LLM AGENT的微服务系统异常检测和根因定位方法

aiboco团队荣获本届挑战赛季军。该团队来自亿阳信通。 方案介绍 本届挑战赛采用开放式赛题&#xff0c;基于建行云龙舟运维平台的稳定性工具和多维监控系统&#xff0c;模拟大型的生活服务APP的生产环境&#xff0c;提供端到端的全链路的日志、指标和调用链数据。参赛队伍在组…

Linux系统——LAMP架构

目录 一、LAMP架构组成 1.LAMP定义 2.各组件的主要作用 3.CGI和FastCGI 3.1CGI 3.3CGI和FastCGI比较 4.PHP 4.1PHP简介 4.2PHP的Opcode语言 4.3PHP设置 二、LAMP架构实现 1.编译安装Apache httpd服务 2.编译安装Mysql 3.编译安装PHP 4.安装论坛 5.搭建博客 W…

spring boot 整合 minio存储 【使用篇】

zi导入依赖 <!--minio--><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.0.3</version></dependency> yml配置&#xff08;默认配置&#xff09; spring:# 配置文件上传大小限制s…

LNMP 架构

环境准备&#xff1a;lnmp 需要安装 nginx mysql php 论坛/博客 软件 使用LNMP架构搭建 论坛 1. 关闭防火墙和和核心防护 systemctl disable --now firewalld setenforce 0 2. 编译安装 nginx 安装依赖包 yum -y install pcre-devel zlib-devel gcc gcc-c make 创建…

The dependencies of some of the beans in the application context form a cycle

1. 场景 项目启动报错如下&#xff1a; 翻译描述信息&#xff1a;应用程序上下文中某些bean的依赖关系形成一个循环 解释报错原因&#xff1a; 图中长方形指示的箭头代表了注入依赖的方向&#xff0c;marketSymbolServiceImpl注入了ownCurrencySettingService&#xff0c;own…