Java实现建造者模式和源码中的应用
Java实现建造者模式(Builder Pattern)
文章目录
- Java实现建造者模式(Builder Pattern)
- 案例:汉堡制作
- 建造者模式的核心角色
- 代码实现:汉堡制作 🍔
- 内部类实现:
- Step 1:产品类 Burger
- Step 2:指挥者 Director
- Step 3:客户端代码
- 结果
- 总结
- 抽象类实现
- Step 1:产品类 Burger
- Step 2:抽象的 Builder 类
- Step 3:具体的 Builder 类
- Step 4:指挥者 Director
- Step 5:客户端代码
- 输出结果
- 总结:使用抽象类的优点
- 源码中的应用
- 1. `StringBuilder` 和 `StringBuffer`
- `2.java.util.stream.Stream.Builder`
- 3.Lombok 中的 `@Builder` 注解
- 示例:使用 `@Builder` 注解
- 总结
建造者模式(Builder Pattern)是一种创建型设计模式,主要用于分步骤构建复杂对象。与工厂模式不同的是,建造者模式允许你逐步地构造对象,并且不同的步骤可以有不同的实现,最终组合成一个复杂的对象。
这个模式尤其适合那些需要在多个步骤中配置或构造对象的场景,例如建造房子、配置计算机、制作汉堡🍔等。而且它可以让代码更加清晰和灵活,因为你可以通过不同的建造者来实现对象的不同变体。
案例:汉堡制作
假设我们有一个汉堡店,他们提供定制汉堡🍔。顾客可以选择面包类型、肉类、蔬菜、酱料等。每个汉堡可以有不同的组合,因此我们使用建造者模式来简化这个复杂的对象创建过程。
建造者模式的核心角色
- Builder(建造者接口/抽象类):定义创建产品对象的各个步骤的接口。
- ConcreteBuilder(具体建造者):实现Builder接口,提供步骤的具体实现。
- Director(指挥者):负责调用建造步骤,指导建造过程。
- Product(产品):最终要创建的复杂对象。
代码实现:汉堡制作 🍔
内部类实现:
Step 1:产品类 Burger
// 产品类:Burger
public class Burger {private String bun; // 面包private String patty; // 肉饼private String sauce; // 酱料private String vegetables; // 蔬菜// 私有化构造函数,防止外部直接实例化private Burger() {}// 内部静态Builder类public static class Builder {private String bun;private String patty;private String sauce;private String vegetables;// 构建面包类型public Builder setBun(String bun) {this.bun = bun;return this;}// 构建肉饼类型public Builder setPatty(String patty) {this.patty = patty;return this;}// 构建酱料类型public Builder setSauce(String sauce) {this.sauce = sauce;return this;}// 构建蔬菜种类public Builder setVegetables(String vegetables) {this.vegetables = vegetables;return this;}// 最终构建出一个完整的Burger对象public Burger build() {Burger burger = new Burger();burger.bun = this.bun;burger.patty = this.patty;burger.sauce = this.sauce;burger.vegetables = this.vegetables;return burger;}}// 打印出汉堡的详细信息@Overridepublic String toString() {return "Burger with " + bun + ", " + patty + ", " + sauce + ", " + vegetables;}
}
Step 2:指挥者 Director
// 指挥者:负责指导汉堡的制作过程
public class Chef {public Burger makeCheeseburger() {return new Burger.Builder().setBun("Sesame Bun") // 芝麻面包.setPatty("Beef Patty") // 牛肉饼.setSauce("Cheese Sauce") // 芝士酱.setVegetables("Lettuce") // 生菜.build();}public Burger makeVeganBurger() {return new Burger.Builder().setBun("Whole Grain Bun") // 全麦面包.setPatty("Vegan Patty") // 素食饼.setSauce("Mustard Sauce") // 芥末酱.setVegetables("Tomato, Lettuce") // 番茄和生菜.build();}
}
Step 3:客户端代码
public class Main {public static void main(String[] args) {Chef chef = new Chef();// 制作一个芝士汉堡Burger cheeseburger = chef.makeCheeseburger();System.out.println(cheeseburger);// 制作一个素食汉堡Burger veganBurger = chef.makeVeganBurger();System.out.println(veganBurger);}
}
结果
当运行这段代码时,输出如下:
Burger with Sesame Bun, Beef Patty, Cheese Sauce, Lettuce
Burger with Whole Grain Bun, Vegan Patty, Mustard Sauce, Tomato, Lettuce
总结
🥷💻 在这个例子中,我们用建造者模式解决了汉堡制作的复杂性:
- 可扩展性:我们可以轻松地添加新步骤(比如加奶酪),或添加新的汉堡类型。
- 清晰性:使用链式调用方式构建对象,每一步都是明确的。
- 灵活性:不同的指挥者可以决定如何组合不同的步骤,产生不同的汉堡变种。
建造者模式非常适合处理需要多步骤配置的复杂对象创建需求,尤其是在需要灵活、可扩展的情况下。💡
抽象类实现
当你有多个复杂对象的构造方式类似,但是具体的构造细节不同,这时可以使用抽象类。抽象类提供一个统一的接口,并允许不同的具体实现类来实现各自的构建步骤。
例如,如果你有多个不同类型的“汉堡”或其他类型的复杂对象,这些对象有相似的结构,但具体的细节不同,那么抽象类就能发挥作用。抽象类提供了基础构建逻辑,而具体的子类负责实现细节
多个复杂对象共享部分构造逻辑:抽象类可以提供共享的构建步骤,具体的构建步骤由子类实现。
强制规范步骤:抽象类可以定义必须实现的方法,这样确保子类都能实现这些步骤。
减少重复代码:如果不同对象之间的构建步骤大部分相同,使用抽象类可以避免重复代码。
Step 1:产品类 Burger
// 产品类:汉堡
public class Burger {private String bun;private String patty;private String sauce;private String vegetables;// 各个字段的设置方法public void setBun(String bun) {this.bun = bun;}public void setPatty(String patty) {this.patty = patty;}public void setSauce(String sauce) {this.sauce = sauce;}public void setVegetables(String vegetables) {this.vegetables = vegetables;}// 输出汉堡详细信息@Overridepublic String toString() {return "Burger with " + bun + ", " + patty + ", " + sauce + ", " + vegetables;}
}
Step 2:抽象的 Builder 类
// 抽象建造者:定义基本的构建步骤
public abstract class BurgerBuilder {protected Burger burger;// 创建新的汉堡public void createNewBurger() {burger = new Burger();}// 具体的构建步骤,由子类实现public abstract void buildBun();public abstract void buildPatty();public abstract void buildSauce();public abstract void buildVegetables();// 返回最终构建的产品public Burger getBurger() {return burger;}
}
Step 3:具体的 Builder 类
// 具体的芝士汉堡建造者
public class CheeseburgerBuilder extends BurgerBuilder {@Overridepublic void buildBun() {burger.setBun("Sesame Bun");}@Overridepublic void buildPatty() {burger.setPatty("Beef Patty");}@Overridepublic void buildSauce() {burger.setSauce("Cheese Sauce");}@Overridepublic void buildVegetables() {burger.setVegetables("Lettuce");}
}// 具体的素食汉堡建造者
public class VeganBurgerBuilder extends BurgerBuilder {@Overridepublic void buildBun() {burger.setBun("Whole Grain Bun");}@Overridepublic void buildPatty() {burger.setPatty("Vegan Patty");}@Overridepublic void buildSauce() {burger.setSauce("Mustard Sauce");}@Overridepublic void buildVegetables() {burger.setVegetables("Tomato, Lettuce");}
}
Step 4:指挥者 Director
// 指挥者:负责调用建造者的构建步骤
public class Chef {private BurgerBuilder burgerBuilder;// 设置当前的建造者public void setBurgerBuilder(BurgerBuilder burgerBuilder) {this.burgerBuilder = burgerBuilder;}// 返回最终构建的汉堡public Burger getBurger() {return burgerBuilder.getBurger();}// 按步骤构建汉堡public void constructBurger() {burgerBuilder.createNewBurger();burgerBuilder.buildBun();burgerBuilder.buildPatty();burgerBuilder.buildSauce();burgerBuilder.buildVegetables();}
}
Step 5:客户端代码
public class Main {public static void main(String[] args) {Chef chef = new Chef();// 制作芝士汉堡BurgerBuilder cheeseburgerBuilder = new CheeseburgerBuilder();chef.setBurgerBuilder(cheeseburgerBuilder);chef.constructBurger();Burger cheeseburger = chef.getBurger();System.out.println(cheeseburger);// 制作素食汉堡BurgerBuilder veganBurgerBuilder = new VeganBurgerBuilder();chef.setBurgerBuilder(veganBurgerBuilder);chef.constructBurger();Burger veganBurger = chef.getBurger();System.out.println(veganBurger);}
}
输出结果
Burger with Sesame Bun, Beef Patty, Cheese Sauce, Lettuce
Burger with Whole Grain Bun, Vegan Patty, Mustard Sauce, Tomato, Lettuce
总结:使用抽象类的优点
- 扩展性更强:如果要添加新的汉堡种类(比如鸡肉汉堡),只需要继承抽象的
BurgerBuilder类并实现它的具体方法,不需要修改已有的代码。 - 代码复用:公共逻辑可以在抽象类中实现,减少子类的代码重复。
- 更灵活的设计:通过定义抽象的步骤,强制每个子类实现各自的步骤,实现了结构的统一性和逻辑的灵活性。
💡 在这种情况下,抽象类为不同类型的汉堡提供了一个标准化的构建流程,同时允许具体的实现类定义各自的细节,使得代码更具灵活性和可维护性。
源码中的应用
Java 标准库中,建造者模式(Builder Pattern)被广泛应用于许多类库和框架,尤其是在创建复杂对象时。这个模式的使用可以大大提高代码的可读性、可维护性,并且能够简化对象的创建过程。
以下是一些经典的 Java 源码应用了建造者模式的例子
1. StringBuilder 和 StringBuffer
StringBuilder 和 StringBuffer 是 Java 中经常使用的用于操作字符串的类,它们可以逐步构建一个字符串,类似于建造者模式。
StringBuilder sb = new StringBuilder();
sb.append("Hello").append(" ").append("World").append("!");System.out.println(sb.toString()); // 输出 "Hello World!"
2.java.util.stream.Stream.Builder
Java 8 引入了 Stream API,Stream.Builder 是一种典型的建造者模式的应用,用于构建 Stream 对象。
Stream.Builder<String> builder = Stream.builder();
builder.add("one").add("two").add("three");Stream<String> stream = builder.build(); // 创建流
stream.forEach(System.out::println);
3.Lombok 中的 @Builder 注解
示例:使用 @Builder 注解
假设我们有一个 Person 类,包含姓名、年龄和地址等字段。我们可以使用 @Builder 注解来简化对象创建。
import lombok.Builder;
import lombok.ToString;@Builder
@ToString
public class Person {private String name;private int age;private String address;
}
通过 @Builder 注解,Lombok 会自动为我们生成一个建造者模式类。接下来我们就可以像这样使用:
public class Main {public static void main(String[] args) {Person person = Person.builder().name("Alice").age(25).address("123 Main St").build();System.out.println(person);}
}
#####*Lombok 自动生成的代码
Lombok 的 @Builder 实际上为我们生成了一个内部的静态 Builder 类,它的结构与我们手动实现的建造者模式非常相似。以 Person 类为例,Lombok 生成的 Builder 类大概是这样:
public class Person {private String name;private int age;private String address;// 私有构造函数,防止直接创建对象private Person(PersonBuilder builder) {this.name = builder.name;this.age = builder.age;this.address = builder.address;}public static PersonBuilder builder() {return new PersonBuilder();}// 静态的内部类 PersonBuilderpublic static class PersonBuilder {private String name;private int age;private String address;public PersonBuilder name(String name) {this.name = name;return this;}public PersonBuilder age(int age) {this.age = age;return this;}public PersonBuilder address(String address) {this.address = address;return this;}public Person build() {return new Person(this);}}@Overridepublic String toString() {return "Person(name=" + this.name + ", age=" + this.age + ", address=" + this.address + ")";}
}
总结
这些 Java 标准库中的类展示了建造者模式在实际开发中的广泛应用。建造者模式通过分步骤地构建复杂对象,提高了代码的灵活性和可读性,避免了冗长的构造函数调用。这使得代码更具扩展性,并且适合于那些对象创建过程中需要多步骤、多参数的场景。
相关文章:
Java实现建造者模式和源码中的应用
Java实现建造者模式(Builder Pattern) 文章目录 Java实现建造者模式(Builder Pattern)案例:汉堡制作建造者模式的核心角色代码实现:汉堡制作 🍔内部类实现:Step 1:产品类…...
Windows安装docker
Windows有两种虚拟号技术,WLS和Hyper-V,因为我的win10是家庭版,所以只能采用WLS来安装docker。 在Windows 10家庭版中,由于默认不包含Hyper-V功能,因此容器功能也不可用。即使启用了Hyper-V,由于Docker De…...
SprinBoot+Vue校园车辆管理系统的设计与实现
目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质…...
【C语言进阶】C语言动态内存管理:深入理解malloc、calloc与realloc
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C语言 “ 登神长阶 ” 🤡往期回顾🤡:C语言自定义类型 🌹🌹期待您的关注 🌹🌹 ❀C语言动态内存管理 &#…...
Java+控制台 图书管理系统
Java控制台 图书管理系统 一、系统介绍二、功能展示1.用户登陆2.普通用户:图书查询、图书借阅、图书归还 、图书列表3.管理员:图书整理、图书添加、图书删除 四、其它1.其他系统实现 一、系统介绍 系统实现了普通用户:图书查询、图书借阅、图书归还 、图…...
gi清除无用缓存
使用 git pull --rebase 的确会对 Git 仓库的大小产生影响,主要是因为每次重新基于最新的代码进行 rebase,Git 会保存历史提交的变动。即使你的实际代码量不多,Git 依然需要存储所有这些历史变更记录,因此可能会导致仓库的大小逐渐…...
云PLM系统对企业影响有哪些?解析云PLM系统的作用
随着企业数字化转型的加速,云PLM产品生命周期管理系统逐渐成为企业提升竞争力、优化资源配置、加速产品上市的重要工具。云PLM系统通过云计算技术,不仅解决了传统PLM系统面临的高昂部署成本、复杂维护、数据共享效率低等问题,还为企业带来了更…...
四、查找算法
文章目录 一、查找算法介绍二、线性查找算法2.1 顺序查找2.2 二分查找(折半查找)2.3 插值查找2.4 斐波拉契(黄金分割法)查找算法 三、树表的查找3.1 二叉排序树3.1.1 引入3.1.2 基本介绍3.1.3 二叉树的遍历3.1.4 二叉树的删除 3.2…...
果蔬识别系统性能优化之路(三)
目录 前情提要遗留问题 解决方案优化查询速度优化ivf初始化的速度 下一步 前情提要 果蔬识别系统性能优化之路(二) 遗留问题 优化同步速度,目前大约30秒,不是一个生产速度 这次来解决遗留问题 通过console,发现两个…...
时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR
时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR 文章目录 一、基本原理二、实验结果三、核心代码四、代码获取五、总结 时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR 一、…...
C#进阶-快速了解IOC控制反转及相关框架的使用
目录 一、了解IOC 1、概念 2、生命周期 二、IOC服务示例 1、定义服务接口 2、实现服务 三、扩展-CommunityToolkit.Mvvm工具包 Messenger信使 方式一(收发消息) 方式二(收发消息) 方式三(请求消息…...
C++内存布局
文章目录 C内存布局1.文字介绍2.图片介绍3.代码介绍 C内存布局 1.文字介绍 1.内核态空间 2.用户态空间 (1)栈区:存储局部变量和函数调用的相关信息,栈的特点是自动分配和释放,由操作系统管理。栈由高地址向低地址生长,通常为0x…...
【Linux 19】线程概念
文章目录 🌈 一、线程的概念⭐ 1. 线程是什么⭐ 2. 线程的优点⭐ 3. 线程的缺点⭐ 4. 线程的异常⭐ 5. 线程的用途 🌈 二、进程和线程⭐ 1. 进程和线程的区别⭐ 2. 进程的多线程共享⭐ 3. 进程和线程的关系⭐ 3. 进程和线程的关系 🌈 一、线程…...
[区间dp]添加括号
题目描述 有一个 n n n 个元素的数组 a a a。不改变序列中每个元素在序列中的位置,把它们相加,并用括号记每次加法所得的和,称为中间和。现在要添上 n − 1 n - 1 n−1 对括号,加法运算依括号顺序进行,得到 n − …...
jenkins流水线+k8s部署springcloud微服务架构项目
文章目录 1.k8s安装2.jenkins安装3.k8s重要知识1.简介2.核心概念3.重要命令1.查看集群消息2.命名空间3.资源创建/更新4.资源查看5.描述某个资源的详细信息6.资源编辑7.资源删除8.资源重启9.查看资源日志10.资源标签 4.k8s控制台1.登录2.界面基本操作1.选择命名空间2.查看命名空…...
安卓开发板_联发科MTK开发评估套件串口调试
串口调试 如果正在进行lk(little kernel ) 或内核开发,USB 串口适配器( USB 转串口 TTL 适配器的简称)对于检查系统启动日志非常有用,特别是在没有图形桌面显示的情况下。 1.选购适配器 常用的许多 USB 转串口的适配器…...
vue+el-table 可输入表格使用上下键进行input框切换
使用上下键进行完工数量这一列的切换 <el-table :data"form.detailList" selection-change"handleChildSelection" ref"bChangeOrderChild" max-height"500"><!-- <el-table-column type"selection" width&quo…...
中国书法——孙溟㠭浅析碑帖《三希堂法帖》
孙溟㠭浅析碑帖《三希堂法帖》 全称是《三希堂石渠宝笈法帖》,是中国清代宫廷刻帖,一共三十二册。 清朝高宗弘历收藏了晋王羲之《快雪时晴帖》,王献之的《中秋帖》,王珣的《伯远帖》三种王氏原墨迹。故而把所藏法书之所…...
深入探讨生成对抗网络(GANs):颠覆传统的AI创作方式
在人工智能的快速发展中,生成对抗网络(Generative Adversarial Networks, GANs)无疑是一个引人注目的技术。自2014年由Ian Goodfellow等人首次提出以来,GANs已经在图像生成、文本生成、视频生成等多个领域展现出了惊人的能力。本文…...
vmware Vnet8虚拟网卡丢失的找回问题
vmware Vnet8虚拟网卡丢失的找回问题 1.打开VMware Workstation 2.然后点击Edit --> Virtual Network Edit --> 打开Virtual Network Edit框 , 3.点击最下面的的Restore Default 按钮, 3.恢复默认设置,这会在网络连接那块可以看到丢失…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
