当前位置: 首页 > news >正文

设计模式Java实现-建造者模式

楔子

小七在2019年的时候,就想写一个关于设计模式的专栏,但是最终却半途而废了。粗略一想,如果做完一件事要100分钟,小七用3分钟热情做的事,最少也能完成10件事情了。所以这一次,一定要把他做完,fighting!

需求背景

以以前小七做的一个政务系统为例,为了符合国标,数据库表需要设计很多字段,大概有100多个。每次new这个实体的时候,都会调用大量的set方法,关键是这100个字段基本不会变,但是他们的组合却经常变,弄得开发的小伙伴们苦不堪言,于是前辈们就重载了很多的构造方法,结果构造方法也爆炸了,导致新来的后浪们差点直接被拍死在了沙滩上。

为了简化代码,咱们这一次就定义一个Student类,里面只包含name和age。

分析设计

因为这个对象的属性很多,且组合方式很自由,如果使用经典的new-set方式,代码大概如下:

BigObject bigObject = new BigObject();
bigObject.setO1("");
bigObject.setO2("");
bigObject.setO3("");
bigObject.setO4("");
bigObject.setO5("");
bigObject.setO6("");
bigObject.setO7("");
bigObject.setO8("");
bigObject.setO9("");
bigObject.setO10("");
...
bigObject.setO100("");   

看起来并不直观。

如果每一个组合就重载一个构造方法,也会产生很多构造方法,并且语义不明,新来的小伙伴会一脸懵逼。

但是如果我们能够抽象一下产品的构建过程,具体建造者类继承自抽象建造者类,实现具体的构建逻辑。指挥者类负责调用具体建造者类的构建方法,完成产品的构建。这样就可以降低客户端代码的复杂度,提高代码的可维护性。

定义类名
产品类Student
抽象建造者类StudentBuilder
具体建造者类StudentActualBuilder
指挥者类Commander

标准建造者模式

UML图

根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码

file

模块名称

builder.demo01

模块地址

https://gitee.com/diqirenge/design-pattern/tree/master/src/main/java/com/run2code/design/creational/builder/demo01

模块描述

经典模式代码示例

代码实现

1、定义产品类

/*** 定义产品类* 关注公众号【奔跑的码畜】,一起进步不迷路** @author 第七人格* @date 2023/11/20*/
public class Student {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

2、定义抽象建造者类

/*** 定义抽象建造者类* 关注公众号【奔跑的码畜】,一起进步不迷路** @author 第七人格* @date 2023/11/20*/
public abstract class StudentBuilder {public abstract void buildName(String name);public abstract void buildAge(int age);public abstract Student makeStudent();
}

3、定义具体建造者类

/*** 定义具体建造者类* 关注公众号【奔跑的码畜】,一起进步不迷路** @author 第七人格* @date 2023/11/20*/
public class StudentActualBuilder extends StudentBuilder {/*** 这里使用组合,将 student 组合到实现类中*/private Student student = new Student();@Overridepublic void buildName(String name) {student.setName(name);}@Overridepublic void buildAge(int age) {student.setAge(age);}@Overridepublic Student makeStudent() {return student;}
}

4、定义指挥者类

/*** 定义指挥者类* 关注公众号【奔跑的码畜】,一起进步不迷路** @author 第七人格* @date 2023/11/20*/
public class Commander {/*** 注入StudentBuilder*/private StudentBuilder studentBuilder;public void setStudentBuilder(StudentBuilder studentBuilder) {this.studentBuilder = studentBuilder;}public Student makeStudent(String name, int age) {this.studentBuilder.buildAge(age);this.studentBuilder.buildName(name);return this.studentBuilder.makeStudent();}
}

5、测试

public class BuilderStudentBuilderTest {@Testpublic void testBuild_01() {System.out.println("==========标准建造者模式开始==========");StudentActualBuilder studentActualBuilder = new StudentActualBuilder();Commander commander = new Commander();commander.setStudentBuilder(studentActualBuilder);// 客户端使用指挥者类创建产品对象,这样可以降低客户端代码的复杂度,提高代码的可维护性。Student student = commander.makeStudent("第七人格", 18);System.out.println(student);System.out.println("==========标准建造者模式结束==========");}
}

6、测试结果

==========标准建造者模式开始==========

Student{name='第七人格', age=18}

==========标准建造者模式结束==========

实现要点

  1. 定义产品类:产品类是最终要构建的对象,包含多个属性和方法。

  2. 定义抽象建造者类:抽象建造者类定义了产品的构建过程,包括各个部分的构建方法和返回最终产品的方法。

  3. 定义具体建造者类:具体建造者类继承自抽象建造者类,实现具体的构建逻辑。

  4. 定义指挥者类:指挥者类负责调用具体建造者类的构建方法,完成产品的构建。

用过StringBuilder的我们知道,StringBuilder有个append方法,我们学着StringBuilder将上面的代码,改为链式调用。

链式调用模式

URL图

file

模块名称

builder.demo02

模块地址

https://gitee.com/diqirenge/design-pattern/tree/master/src/main/java/com/run2code/design/creational/builder/demo02

模块描述

建造者-链式调用

代码实现

/*** 链式调用建造者示例* 关注公众号【奔跑的码畜】,一起进步不迷路** @author 第七人格* @date 2023/11/20*/
public class Student02Builder {/*** 姓名*/private String name;/*** 年龄*/private int age;/*** 学生类的构造函数** @param name 的名字* @param age  年龄*/Student02Builder(String name, int age) {this.name = name;this.age = age;}/*** 构建器(本质上就是指挥者Commander)** @return {@link StudentBuilder}*/public static Student02Builder.StudentBuilder builder() {// 构造一个StudentBuilder对象return new Student02Builder.StudentBuilder();}/*** 学生构建器(相当于StudentBuilder及其实现类StudentActualBuilder)** @author 第七人格* @date 2020/12/02*/public static class StudentBuilder {private String name;private int age;public StudentBuilder() {}public Student02Builder.StudentBuilder name(String name) {this.name = name;// 返回自身(StudentBuilder),以便链式调用return this;}public Student02Builder.StudentBuilder age(int age) {this.age = age;// 返回自身(StudentBuilder),以便链式调用return this;}/*** 构建** @return {@link Student02Builder}*/public Student02Builder build() {// 构造一个Student对象,其中的属性直接从外部传入return new Student02Builder(this.name, this.age);}@Overridepublic String toString() {return "Student.StudentBuilder(name=" + this.name + ", age=" + this.age + ")";}}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

测试

@Test
public void testBuild_02() {System.out.println("==========工作中常用-建造者模式开始==========");System.out.println(Student02Builder.builder().age(18).name("第七人格").build());System.out.println("==========工作中常用-建造者模式开始==========");
}

测试结果

==========链式调用-建造者模式开始==========

Student{name='第七人格', age=18}

==========链式调用-建造者模式开始==========

实现要点

1、使用静态方法替换指挥者Commander

public static Student02Builder.StudentBuilder builder() {// 构造一个StudentBuilder对象return new Student02Builder.StudentBuilder();
}

2、使用内部类替换StudentBuilder及StudentActualBuilder

3、内部类中设置属性的时候,返回自身,以便链式调用

面对对象面对君,不负代码不负卿

相关文章:

设计模式Java实现-建造者模式

楔子 小七在2019年的时候,就想写一个关于设计模式的专栏,但是最终却半途而废了。粗略一想,如果做完一件事要100分钟,小七用3分钟热情做的事,最少也能完成10件事情了。所以这一次,一定要把他做完&#xff0…...

微博视频怎么下载无水印

在当今社交媒体时代,微博已经成为人们获取信息、分享生活的重要平台之一。许多人在浏览微博时常常遇到一个问题:如何下载微博视频而不留下烦人的水印呢?今天,我将分享一些神秘的方法,让你轻松解锁微博视频的无水印下载技巧。 第…...

为什么要梯度累积

文章目录 梯度累积什么是梯度累积如何理解理解梯度累积梯度累积的工作原理 梯度累积的数学原理梯度累积过程如何实现梯度累积 梯度累积的可视化 梯度累积 什么是梯度累积 随着深度学习模型变得越来越复杂,模型的训练通常需要更多的计算资源,特别是在训…...

知识图谱在提升大语言模型性能中的应用:减少幻觉与增强推理的综述

幻觉现象指的是模型在生成文本时可能会产生一些听起来合理但实际上并不准确或相关的输出,这主要是由于模型在训练数据中存在知识盲区所致。 为了解决这一问题,研究人员采取了多种策略,其中包括利用知识图谱作为外部信息源。知识图谱通过将信息…...

P8800 [蓝桥杯 2022 国 B] 卡牌

P8800 [蓝桥杯 2022 国 B] 卡牌 分析 “最多” -- 二分 1.二分区间(凑齐的卡牌套数): l:a[]min;r:(a[]b[])max 2.check(x): (1)for循环内: 判断x - a[i…...

MySQL商城数据表(80-84)

80商品规格值表 DROP TABLE IF EXISTS niumo_spec_items; CREATE TABLE niumo_spec_items (itemId int(11) NOT NULL AUTO_INCREMENT COMMENT 自增ID,shopId int(11) NOT NULL DEFAULT 0 COMMENT 店铺ID,catId int(11) NOT NULL DEFAULT 0 COMMENT 类型ID,goodsId int(11) NOT…...

使用Gitbook生成电子书

背景 《Google工程实践文档》相对原文Google’s Engineering Practices documentation ,部分内容过时了。需要更新中文版,并使用Gitbook把Markdown文件转换成对应的PDF电子书。   上一次生成PDF电子书是5年前,当时生成电子书的环境早已不在…...

设计模式之传输对象模式

在编程江湖里,有一种模式,它如同数据的“特快专递”,穿梭于系统间,保证信息的快速准确送达,它就是——传输对象模式(Data Transfer Object, DTO)。这不仅仅是数据的搬运工,更是提升系…...

Re69:读论文 LaMDA: Language Models for Dialog Applications

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称:LaMDA: Language Models for Dialog Applications ArXiv网址:https://arxiv.org/abs/2201.08239 本文介绍谷歌提出的对话大模型LaMDA,主要关注对各项指标&#x…...

算法学习:二分查找

🔥 引言 在现代计算机科学与软件工程的实践中,高效数据检索是众多应用程序的核心需求之一。二分查找算法,作为解决有序序列查询问题的高效策略,凭借其对数时间复杂度的优越性能,占据着算法领域里举足轻重的地位。本篇内…...

github提交代码失败解决方案

1.打开github.push 工具 ​ 如果未安装github客户端请参考附录github 安装配置 2.设置Git的user name和email git config --global user.name "yourname" git config --global user.email "youremail" 3.生成SSH密钥 查看是否已经有了ssh密钥&#xff1…...

连锁收银系统总仓到门店库存调拨操作教程

1、进入系统后台,系统后台登录网址: 2、点击商品>门店调拨 3、选择调出仓库和调入门店 4、可选择添加商品逐个进行调拨,也可以批量导入需要调拨的商品 然后点击确定。 5、新增调拨后,系统会显示“待出库”状态 6、仓库已经准备…...

公网tcp转流

之前做过几次公网推流的尝试, 今天试了UDP推到公网, 再用TCP从公网拉下来, 发现不行, 就直接改用TCP转TCP了. 中间中转使用的python脚本, 感谢GPT提供技术支持: import socket import threadingdef tcp_receiver(port, forward_queue):"""接收TCP数据并将其放入…...

【Linux 基础 IO】文件系统

文章目录 1.初步理解文件2. fopen ( )的详解 1.初步理解文件 🐧① 打开文件: 本质是进程打开文件; 🐧②文件没有被打开的时候在哪里呢? ----- 在磁盘中; 🐧③进程可以打开很多个文件吗&#xff…...

Chrome浏览器安装React工具

一、如果网络能访问Google商店,直接安装官方插件即可 二、网络不能访问Google商店,使用安装包进行安装 1、下载react工具包 链接:https://pan.baidu.com/s/1qAeqxSafOiNV4CG3FVVtTQ 提取码:vgwj 2、chrome浏览器安装react工具…...

React常用组件分享

1、轮播组件: React Awesome Slider React Slider Carousel Component - react-awesome-slider...

JSON原生AJAX

文章目录 JSONFastjsonfastjson引入fastjson 常用APIfastjson作用常用API使用实例 ajax和json综合(重要)请求参数和响应数据都是普通字符串响应数据改为json格式请求和响应都是js数据封装到Result类和抽取到BaseController 原生AjaxAJAX的执行流程XMLHttpRequest对象使用原生的…...

Go图片列表

需求 在一个页面浏览目录下所有图片 代码 package mainimport ("net/http""fmt""io/ioutil""sort""strings""strconv""net/url" )func handleRequest(w http.ResponseWriter, r *http.Request) { de…...

1.4 初探JdbcTemplate操作

实战目的 掌握Spring框架中JdbcTemplate的使用,实现对数据库的基本操作。理解数据库连接池的工作原理及其在实际开发中的重要性。通过实际操作,加深对Spring框架中ORM(对象关系映射)的理解。 关键技术点 JdbcTemplate操作&…...

React 第二十一章 Portals

Portals 被翻译成传送门,是 React 库中的一个特性,它允许开发者将子组件渲染到父组件 DOM 层次结构之外的其他地方。 React 组件通常是在其父组件的 DOM 层次结构中渲染的,这意味着它们的输出会被插入到父组件的某个 DOM 元素中。然而&#…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...