设计模式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、内部类中设置属性的时候,返回自身,以便链式调用

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

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

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

相关文章

Windows常用快捷键与CMD常用命令

1.win系列快捷键使用 WinD,快速进入桌面 WinE,打开我的电脑(文件资源管理器) WinI,打开设置界面 WinL,快速锁屏 WinM,最小化所有窗口 WinShiftM,还原最小化的窗口 WinV&#…

为什么下载卡在idealTree:NodeJS: sill idealTree buildDeps

可能使用的是npm config set registry https://registry.npm.taobao.org而这个镜像文件已经过期了 解决方法如下: 先使用 npm cache clean --force 清除缓存 再切换镜像源 再使用npm config get registry 进行查看是否换源成功 再使用 npm install -g vue/cli 就…

【算法】滑动窗口——长度最小的子数组

本篇文章是用一个实例来介绍常用算法之一“滑动窗口”的相关概念,有需要借鉴即可。 目录 1.题目2.暴力求解2.1暴力求解思路:2.2时间复杂度是多少? 3.暴力求解的优化3.1固定left的情况下,优化right的次数。3.2sum求值优化3.3不同组…

商城数据库88张表结构完整示意图81~88及总览图(十六)

八十一: 八十二: 八十三: 八十四: 八十五: 八十六: 八十七: 八十八: 总览图:

Redis开源社区持续壮大,华为云为Valkey项目注入新的活力

背景 今年3月21日,Redis Labs宣布从Redis 7.4版本开始,将原先比较宽松的BSD源码使用协议修改为RSAv2和SSPLv1协议,意味着 Redis在OSI(开放源代码促进会)定义下不再是严格的开源产品。Redis官方表示,开发者…

websevere服务器从零搭建到上线(四)|muduo网络库的基本原理和使用

文章目录 muduo源码编译安装muduo框架讲解muduo库编写服务器代码示例代码解析用户连接的创建和断开回调函数用户读写事件回调 使用vscode编译程序配置c_cpp_properties.json配置tasks.json配置launch.json编译 总结 muduo源码编译安装 muduo依赖Boost库,所以我们应…

webpack与vite

webpack 使用步骤: 初始化项目 pnpm init -y安装依赖webpack、webpack-cli在项目中创建src目录,然后编写代码(index.js)执行pnpm weboack来对代码进行打包(打包后观察dist文件夹) 配置古文件(w…

使用ThemeRoller快速实现前端页面风格美化

使用ThemeRoller快速实现前端页面风格美化 文章目录 使用ThemeRoller快速实现前端页面风格美化一、ThemeRoller二、使用方法1.基本操作面板介绍2.直接用现成的配色风格——Gallery画廊3.自定义风格——Roll Your Own4.下载风格包并应用到页面 一、ThemeRoller ThemeRoller是jQ…

基于java的CRM客户关系管理系统的设计与实现(论文 + 源码 )

【免费】基于Java的CRM客户关系管理系统的设计和实现.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89273409 基于Java的CRM客户关系管理系统的设计与实现 摘 要 随着互联网的高速发展,市场经济的信息化,让企业之间的竞争变得&#xff0…

纯血鸿蒙APP实战开发——页面间共享组件实例的案例

介绍 本示例提供组件实例在页面间共享的解决方案:通过Stack容器,下层放地图组件,上层放Navigation组件来管理页面,页面可以共享下层的地图组件,页面中需要显示地图的区域设置为透明,并参考触摸交互控制&am…

各城市-人口就业和工资数据(1978-2022年)

这份数据收集了1978年至2022年间300多个地级市的人口、就业和工资等数据。涵盖的指标包括从业人员数量、平均工资水平、人口密度等,通过这些数据可以深入了解中国各地城市的人口结构、就业状况以及工资水平的变化趋势。这些数据对于研究城市发展、劳动力市场以及区域…

论文架构介绍

论文架构 背景:建议2段左右完成,字数控制在500左右为佳,对应子题目1过渡段:写150字左右的过渡段,承上启下,回答部分子题目2、3的要求正文实践部分:一般3-7个论点,根据题目的要求来看…

C++构造函数和析构函数的调用顺序

一般情况下,调用析构函数的次序正好与调用构造函数的次序相反,也就是最先被调用的构造函数,其对应的析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。 当然对象的构造函数和析构函数调用时机和…

力扣100284. 有效单词(C++)

【题解】 (实际在力扣中运行的代码只需要把下方的check函数放到力扣作答区给的模板中就可以) #include <bits/stdc.h> #include <iostream> #include <vector> #include <string> #include <cctype> #include <cstring> #include <st…

融知财经:期货交易的规则和操作方法

期货交易是指在未来的某一特定时期&#xff0c;买卖双方通过签订合约的方式&#xff0c;约定以某种价格买卖一定数量的某种商品或资产的行为。期货交易的规则和操作方法如下&#xff1a; 期货交易的规则和操作方法 1、双向交易&#xff1a; 期货市场允许投资者进行多头&#xf…

Python ArcPy批量将大量栅格文件的投影坐标系转为地理坐标系

本文介绍基于Python语言中的ArcPy模块&#xff0c;批量将多个遥感影像由投影坐标系转为地理坐标系的方法。 在之前的文章中&#xff0c;我们介绍过将单独1景遥感影像的投影坐标系转为地理坐标系的方法&#xff0c;大家可以参考文章投影坐标系转为地理坐标系&#xff1a;GDAL命令…

笔记86:关于【#ifndef + #define + #endif】的用法

当你在编写一个头文件&#xff08;例如 pid_controller.h&#xff09;时&#xff0c;你可能会在多个源文件中包含它&#xff0c;以便在这些源文件中使用该头文件定义的函数、类或其他声明。如果你在多个源文件中都包含了同一个头文件&#xff0c;那么当你将整个工程统一编译&am…

第六节课《Lagent AgentLego 智能体应用搭建》

PDF链接&#xff1a;https://pan.baidu.com/s/1JFtvBWgEGFWJq8pHafvIUg?pwd6666 提取码&#xff1a;6666 Lagent & AgentLego 智能体应用搭建_哔哩哔哩_bilibili https://github.com/InternLM/Tutorial/blob/camp2/agent/README.md InternStudio 一、为什么需要agent…

基于JSP的酒店客房管理系统(三)

目录 第四章 系统各模块的实现 4.1客房管理系统首页的实现 4.1.1 客房管理系统首页概述 4.2客房管理系统前台的实现 4.2.1 客房管理系统前台概述 4.2.2 客房管理系统前台实现过程 4.2.3 预定客房信息及客房信息的查询 4.3客房管理系统后台的实现 4.3.1 客房管理系统后…

微搭低代码入门05文件的上传和下载

目录 1 创建数据源2 创建应用3 创建页面4 设置导航功能5 文件上传6 文件下载总结 小程序中&#xff0c;我们通常会有文件的上传和下载的需&#xff0c;在微搭中&#xff0c;文件是存放在云存储中&#xff0c;每一个文件都会有一个唯一的fileid&#xff0c;我们本篇就介绍如何通…