【Java开发】设计模式 03:建造者模式

news2025/7/18 7:35:37

1 建造者模式介绍

建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。

当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

📌 场景

当一个类的构造函数参数超过4个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象。 例如我们现在有如下一个类计算机类Computer,其中cpu与ram是必填参数,而其他3个是可选参数,那么我们如何构造这个类的实例呢,通常有两种常用的方式:

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选
}

① 折叠构造函数模式

public class Computer {

    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选,默认为0
    private String keyboard;//可选,默认为罗技键盘
    private String display;//可选,默认为三星显示器

    public Computer(String cpu, String ram) {
        this(cpu, ram, 0);
    }
    public Computer(String cpu, String ram, int usbCount) {
        this(cpu, ram, usbCount, "罗技键盘");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard) {
        this(cpu, ram, usbCount, keyboard, "三星显示器");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard, String display) {
        this.cpu = cpu;
        this.ram = ram;
        this.usbCount = usbCount;
        this.keyboard = keyboard;
        this.display = display;
    }
}

② Javabean模式

public class Computer {

    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选

    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }
    public String getRam() {
        return ram;
    }
    public void setRam(String ram) {
        this.ram = ram;
    }
    public int getUsbCount() {
        return usbCount;
    }
...
}

这也可用lombok依赖包的@Data注解替代~

📌 两种方式的弊端

第一种使用和阅读不方便,当使用该类的构造函数时,需要搞清楚各参数的含义,而且还是按照严格的顺序。

第二种由于类的属性是分布设置的,那么构建过程中对象的状态容易发生变化,容易出错。

那么builder模式可以较好地解决以上问题!

2 构建者模式实现

📌 步骤

  1. 在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。

  1. 在Computer中创建一个private的构造函数,参数为Builder类型

  1. 在Builder中创建一个public的构造函数,参数为Computer中必填的那些参数,cpu 和ram。

  1. 在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例

  1. 在Builder中创建一个build()方法,在其中构建Computer的实例并返回

也可直接使用lombok依赖包的@Builder注解一键解决。

📌 具体代码

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选,默认为0
    private String keyboard;//可选,默认为罗技键盘
    private String display;//可选,默认为三星显示器

    private Computer(Builder builder){
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }
    public static class Builder{
        private String cpu;//必须
        private String ram;//必须
        private int usbCount;//可选
        private String keyboard;//可选
        private String display;//可选

        public Builder(String cup,String ram){
            this.cpu=cup;
            this.ram=ram;
        }

        public Builder setUsbCount(int usbCount) {
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) {
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) {
            this.display = display;
            return this;
        }
        public Computer build(){
            return new Computer(this);
        }
    }
}

📌 使用

Computer computer = new Computer.Builder("AMD","小米")
        .setUsbCount(0)
        .setKeyboard("罗技")
        .setDisplay("三星24寸").build();

📌 @Builder注解一键解决

@Builder
public class Computer {
    private String cpu;//可选
    private String ram;//可选
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选
}

class test{
    public static void main(String[] args) {
        Computer computer = Computer.builder().cpu("AMD").ram("金士顿")
                .usbCount(0)
                .keyboard("罗技")
                .display("三星24寸")
                .build();
    }
}

使用方式稍微不一样~

3 传统建造者模式

上面的内容是Builder在Java中一种简化的使用方式,经典的Builder 模式与其有一定的不同,如UML图:

📌 各角色

  • Product: 最终要生成的对象,例如 Computer实例。

  • Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct(),例如 ComputerBuilder抽象类。

  • ConcreteBuilder: Builder的实现类,如LenovoComputerBuilder类和MacComputerBuilder类。

  • Director: 决定如何构建最终产品的算法, 其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,例如 ComputerDirector类。

等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品。

📌 1.目标Computer类

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选,默认为0
    private String keyboard;//可选,默认为罗技键盘
    private String display;//可选,默认为三星显示器

    public Computer(String cpu, String ram) {
        this.cpu = cpu;
        this.ram = ram;
    }
    public void setUsbCount(int usbCount) {
        this.usbCount = usbCount;
    }
    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }
    public void setDisplay(String display) {
        this.display = display;
    }
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram='" + ram + '\'' +
                ", usbCount=" + usbCount +
                ", keyboard='" + keyboard + '\'' +
                ", display='" + display + '\'' +
                '}';
    }
}

📌 2.抽象构建者类

public abstract class ComputerBuilder {

    public abstract void setUsbCount();
    public abstract void setKeyboard();
    public abstract void setDisplay();

    public abstract Computer getComputer();
}

📌 3.实体构建者类

public class LenovoComputerBuilder extends ComputerBuilder{
    private Computer computer;
    public LenovoComputerBuilder(String cpu, String ram) {
        computer=new Computer(cpu,ram);
    }
    @Override
    public void setUsbCount() {
        computer.setUsbCount(4);
    }
    @Override
    public void setKeyboard() {
        computer.setKeyboard("联想键盘");
    }
    @Override
    public void setDisplay() {
        computer.setDisplay("联想显示器");
    }
    @Override
    public Computer getComputer() {
        return computer;
    }
}
public class MacComputerBuilder extends ComputerBuilder{

    private Computer computer;

    public MacComputerBuilder(String cpu, String ram) {
        computer = new Computer(cpu, ram);
    }

    @Override
    public void setUsbCount() {
        computer.setUsbCount(2);
    }
    @Override
    public void setKeyboard() {
        computer.setKeyboard("苹果键盘");
    }
    @Override
    public void setDisplay() {
        computer.setDisplay("苹果显示器");
    }
    @Override
    public Computer getComputer() {
        return computer;
    }
}

📌 4.指导者类(Director)

public class ComputerDirector {
    public void makeComputer(ComputerBuilder builder){
        builder.setUsbCount();
        builder.setDisplay();
        builder.setKeyboard();
    }
}

📌 5.使用

首先生成一个director,然后生成一个目标builder ,接着使用director组装builder,组装完毕后使用builder创建产品实例。

    ComputerDirector director = new ComputerDirector();//1
    
    ComputerBuilder macBuilder = new MacComputerBuilder("I5处理器","三星125");//2
    director.makeComputer(macBuilder);//3
    Computer macComputer=macBuilder.getComputer();//4
    System.out.println("mac computer:"+macComputer.toString());
    
    ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222");
    director.makeComputer(lenovoBuilder);
    Computer lenovoComputer=lenovoBuilder.getComputer();
    System.out.println("lenovo computer:"+lenovoComputer.toString());

📌 总结

其实之前用的是的变种, 首先其省略了director 这个角色,将构建算法交给了client端,其次将builder 写到了要构建的产品类里面,最后采用了链式调用。

秒懂设计模式之建造者模式(Builder pattern) - 知乎 (zhihu.com)

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

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

相关文章

【论文研读 上】基于开源软件的无人机飞行仿真 鹿珂珂,刘登攀,王超

基于开源软件的无人机飞行仿真 摘 要 飞行控制算法设计和仿真是无人机研制的关键步骤。为了缩短无人机飞行控制算法设计周期和试验成本,对无人 机纵向和侧向控制算法进行了设计,并基于开源软件开发了固定翼无人机可视化的飞行仿真系统, 固定…

Kafka入门教程

1 Kafka安装 1.1 压缩包安装 1.1.1 JDK环境安装 Kafka是依赖JDK环境的,所以需要事先安装好JDK 下载JDK安装包: Oracle JDK8下载SSH上传到想要安装的目录,比如 /opt.然后使用tar -zxvf jdk-8u351-linux-x64.tar.gz命令解压 添加环境变量 vi /etc/profile,输入如下内容保存后…

【9.数据页结构】

概述 InnoDB 的数据是按「数据页」为单位来读写的,也就是说,当需要读一条记录的时候,并不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存。数据库的 I/O 操作的最小单位是页,InnoDB 数据页…

【Linux内核三】网络丢包debug案例

👉个人主页:highman110 👉作者简介:一名硬件工程师,持续学习,不断记录,保持思考,输出干货内容 目录 前言 测试环境 测试现象 ​编辑 定位过程 ​编辑 优化手段 1、加大ring buffer …

X86ARM @Linux平台cache eviction功能测试

经典的ARM处理器高速缓存工作原理: 高速缓存内部结构:

Qt样式表

1>样式表介绍 样式表可通过 QApplication::setStyleSheet()函数将其设置到整个应用程序上,也可以使用 QWidget::setStyleSheet()将其设置到指定的部件或子部件上,不同级别均可设置样式表,称为样式表的层叠。样式表也可通过设计模式编辑样…

vue中render函数的作用及解析

在vue脚手架的main.js文件中,存在这样一段代码: 意思是对vue实例的配置,其中render函数的作用是,将h创建的Node节点信息return返回给Vue.js底层处理文件中的beforeMount()生命周期钩子函数,让其将Node节点信息在界面中…

智能优化算法之蚁群算法

1、蚁群算法概述 蚁群算法(Ant Colony Algorithm, ACA) 由Marco Dorigo于1992年在他的博士论文中首次提出, 该算法模拟了自然界中蚂蚁的觅食行为。 蚂蚁在寻找食物源时, 会在其经过的路径上释放一种信息素, 并能够感知…

配对变量t检验

区别双变量t检验,见:https://mp.csdn.net/postedit/100640098 配对变量为两两相关的变量:如敷药前后体重变化。 要求:两变量服从正态分布。 SPSS演练 打开数据文件:ptest.sav 载地址:https://download.c…

vscode环境配置文件生成

使用vscode进行C开发时,除了需要安装相应的插件(例如:C/C、CMake、MySql等)外,还需要对相应的开发环境进行配置,和vs中的环境配置道理相通。一、编译文件介绍配置 C 环境时,会生成.vscode 文件夹…

记录一次消毒碗柜维修

现象:按开始消毒后马上停止,但可以一直按着按钮,就可以消毒,并且30分钟后可以自动停止。分析:消毒柜里面控制器就这3个1 开关只是触发通电,弹起就断开,按下可以接通,判断该零件正常2…

STM32感应开关盖垃圾桶

目录 项目需求 项目框图 ​编辑 硬件清单 sg90舵机介绍及实战 sg90舵机介绍 角度控制 SG90舵机编程实现 超声波传感器介绍及实战 超声波传感器介绍 超声波编程实战 项目设计及实现 项目需求 检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖…

Hadoop入个门

文章目录1️⃣、Hadoop概述1.1、Hadoop是什么1.2、三大发行版本1.3、优势1.4、组成HDFSYARNMapReduceHDFS、YARN、MapReduce三者关系1.6、大数据技术生态体系image-202303111027195802️⃣、Hadoop运行环境搭建2.1、虚拟机环境准备2.2、克隆虚拟机2.3、在hadoop2上安装JDK2.4、…

cocoscreator+TS 遇到的问题

报错Can not preload the scene "game2" because it is not in the build settings.报错 1209, please go to https://github.com/cocos-creator/engine/blob/develop/EngineErrorMap.md#1209 to see details. Arguments: game2(env: Windows,mg,1.06.2303022; lib: …

掌握Shell脚本的if语句,让你的代码更加精准和高效

前言 大家好,我是沐风晓月,本文首发于csdn, 作者: 我是沐风晓月。 文章收录于 我是沐风晓月csdn专栏 【系统架构实战】专栏中的【shell脚本入门到精通】专栏。 本专栏从零基础带你层层深入,学会shell脚本,不是梦。 &…

核心系统国产平台迁移验证

核心系统国产平台迁移验证 摘要:信息技术应用创新,旨在实现信息技术领域的自主可控,保障国家信息安全。金融领域又是关系国家经济命脉的行业,而对核心交易系统的信息技术应用创新是交易所未来将要面临的重大挑战。为了推进国产化进…

云数据库RDS介绍

RDS介绍 关系型数据库(relational database service,简称RDS),是一种可靠、可弹性伸缩的在线数据库服务。 1)基于分布式文件系统和SSD盘高性能存储 2)支持MySQL、SQL Server、PostgreSQL、MariaDB TX引擎 …

原来不用控制台,也可以轻松调试CSS呀

Ⅰ. 作用 用于调试CSS , 比控制台添更加方便,不需要寻找 ;边添加样式,边可以查看效果,适合初学者对CSS 的理解和学习; Ⅱ. 快速实现(两边) ① 显示这个样式眶 给 head 和 style 标签添加一个…

YOLOS学习记录

在前面,博主已经完成了YOLOS项目的部署与调试任务,并在博主自己构造的数据集上进行了实验,实验结果表明效果并不显著,其实这一点并不意外,反而是在情理之中。众所周知,Transformer一直以来作为NLP领域的带头…

独立开发者案例:每周4h月入数万刀;国家数据局与时代红利;创业前先买个域名;工程师成长最重要的是什么 | ShowMeAI周刊

这是ShowMeAI周刊的第6期。聚焦AI领域本周热点,及其在各圈层泛起的涟漪;关注AI技术进步,并提供我们的商业洞察。欢迎关注与订阅!👀日报合辑 ⌛ 独立开发者案例:每周只工作4小时,独立开发者打造月…