Java实现建造者模式和源码中的应用

🎯 设计模式专栏,持续更新中, 欢迎订阅: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)是一种创建型设计模式,主要用于分步骤构建复杂对象。与工厂模式不同的是,建造者模式允许你逐步地构造对象,并且不同的步骤可以有不同的实现,最终组合成一个复杂的对象。

这个模式尤其适合那些需要在多个步骤中配置或构造对象的场景,例如建造房子、配置计算机、制作汉堡🍔等。而且它可以让代码更加清晰灵活,因为你可以通过不同的建造者来实现对象的不同变体。

案例:汉堡制作

假设我们有一个汉堡店,他们提供定制汉堡🍔。顾客可以选择面包类型、肉类、蔬菜、酱料等。每个汉堡可以有不同的组合,因此我们使用建造者模式来简化这个复杂的对象创建过程。

建造者模式的核心角色

  1. Builder(建造者接口/抽象类):定义创建产品对象的各个步骤的接口。
  2. ConcreteBuilder(具体建造者):实现Builder接口,提供步骤的具体实现。
  3. Director(指挥者):负责调用建造步骤,指导建造过程。
  4. 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
总结

🥷💻 在这个例子中,我们用建造者模式解决了汉堡制作的复杂性:

  1. 可扩展性:我们可以轻松地添加新步骤(比如加奶酪),或添加新的汉堡类型。
  2. 清晰性:使用链式调用方式构建对象,每一步都是明确的。
  3. 灵活性:不同的指挥者可以决定如何组合不同的步骤,产生不同的汉堡变种。

建造者模式非常适合处理需要多步骤配置的复杂对象创建需求,尤其是在需要灵活、可扩展的情况下。💡

抽象类实现

当你有多个复杂对象的构造方式类似,但是具体的构造细节不同,这时可以使用抽象类。抽象类提供一个统一的接口,并允许不同的具体实现类来实现各自的构建步骤。

例如,如果你有多个不同类型的“汉堡”或其他类型的复杂对象,这些对象有相似的结构,但具体的细节不同,那么抽象类就能发挥作用。抽象类提供了基础构建逻辑,而具体的子类负责实现细节

多个复杂对象共享部分构造逻辑:抽象类可以提供共享的构建步骤,具体的构建步骤由子类实现。

强制规范步骤:抽象类可以定义必须实现的方法,这样确保子类都能实现这些步骤。

减少重复代码:如果不同对象之间的构建步骤大部分相同,使用抽象类可以避免重复代码。

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
总结:使用抽象类的优点
  1. 扩展性更强:如果要添加新的汉堡种类(比如鸡肉汉堡),只需要继承抽象的 BurgerBuilder 类并实现它的具体方法,不需要修改已有的代码。
  2. 代码复用:公共逻辑可以在抽象类中实现,减少子类的代码重复。
  3. 更灵活的设计:通过定义抽象的步骤,强制每个子类实现各自的步骤,实现了结构的统一性和逻辑的灵活性。

💡 在这种情况下,抽象类为不同类型的汉堡提供了一个标准化的构建流程,同时允许具体的实现类定义各自的细节,使得代码更具灵活性和可维护性。

源码中的应用

Java 标准库中,建造者模式(Builder Pattern)被广泛应用于许多类库和框架,尤其是在创建复杂对象时。这个模式的使用可以大大提高代码的可读性、可维护性,并且能够简化对象的创建过程

以下是一些经典的 Java 源码应用了建造者模式的例子

1. StringBuilderStringBuffer

StringBuilderStringBuffer 是 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 标准库中的类展示了建造者模式在实际开发中的广泛应用。建造者模式通过分步骤地构建复杂对象,提高了代码的灵活性可读性,避免了冗长的构造函数调用。这使得代码更具扩展性,并且适合于那些对象创建过程中需要多步骤、多参数的场景。

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

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

相关文章

ubuntu安装mysql 8.0忘记root初始密码,如何重新修改密码

1、停止mysql服务 $ service mysql stop 2、修改my.cnf文件 # 修改my.cnf文件&#xff0c;在文件新增 skip-grant-tables&#xff0c;在启动mysql时不启动grant-tables&#xff0c;授权表 $ sudo vim /etc/mysql/my.cnf [mysqld] skip-grant-tables 3、启动mysql服务 servic…

【四】k8s部署 TDengine集群

k8s部署 TDengine集群 目录 k8s部署 TDengine集群 一、在 Kubernetes 上部署 TDengine 集群 第一步&#xff1a;创建命名空间 第二步&#xff1a;从yaml创建有状态服务 StatefulSet 第三步&#xff1a;配置 Service 服务 二、集群测试 一、在 Kubernetes 上部署 TDengine…

实习期间git的分枝管理以及最常用的命令

各位找工作实习的友友在工作之前一定要把git的相关知识掌握呀&#xff0c;我实现期间被leader说过关于git规范的相关问题了 目前已更新系列&#xff1a; 当前&#xff1a;:实习期间git的分枝管理以及最常用的命令 Redis高级-----持久化AOF、RDB原理 Redis高级---面试总结5种…

Android SPN/PLMN 显示逻辑简介

功能描述 当设备驻网后(运营商网络),会在状态栏、锁屏界面、下拉控制中心显示运营商的名称。 此名称来源有两种: 1、SPN(Service Provider Name) 2、PLMN (Public Land Mobile Name) 功能AOSP默认逻辑SPN提供SIM卡的运营商名称预置在SIM EF中,SIM卡发行运营商名称…

微软九月补丁星期二发现了 79 个漏洞

微软将在2024 年 9 月补丁星期二修复 79 个漏洞。 微软有证据表明&#xff0c;发布的四个漏洞被野外利用和/或公开披露&#xff1b;所有四个漏洞均已在CISA KEV上列出。微软还在修补四个关键的远程代码执行 (RCE) 漏洞。 不同寻常的是&#xff0c;微软本月尚未修补任何浏览器…

redis详细解析和配置选择

Redis是一个开源的、使用ANSI C语言编写的、基于内存亦可持久化的日志型Key-Value非关系型数据库。它以其高性能、丰富的数据结构和灵活的数据模型而广受欢迎&#xff0c;被广泛应用于缓存、消息队列、实时数据处理等多种场景。以下是对Redis的详细解析和配置选择的详细阐述。 …

AI替代插画师跟设计师?不用焦虑!

一个固定的工作流&#xff0c; 一个训练好的lora模型 输入一段提示词 二三十秒的时间&#xff0c;就能生成一张精致美观有韵味的中秋国风插画 这张不喜欢&#xff0c;改下提示词重新生成一张不一样的。还是二十几秒 同样的插画&#xff0c;你用手绘&#xff0c;从起稿到上…

【Unity】为脚本添加头部注释

1 前言 默认创建的脚本头部是没有注释的&#xff0c;有时候我们想要在创建脚本时在脚本内容的最前面加上一个注释来标注脚本的相关信息&#xff0c;比如创建者、创建时间、描述等等。那么提供有两种实现方式。 2 方法 2.1 修改Unity的脚本Script 打开Unity Hub&#xff0c;找…

C语言编译原理

目录 一、C语言的编译过程 二、预处理 三、编译阶段 3.1 词法分析&#xff08;Lexical Analysis&#xff09; 3.2 语法分析&#xff08;Syntax Analysis&#xff09; 语法分析的主要步骤&#xff1a; 语法分析的关键技术&#xff1a; 构建AST&#xff1a; 符号表的维护…

【Linux进程】Linux Shell编程实战:构建简易脚本示例与技巧详解

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;Linux “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;暂无 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀Linux进程 &#x1f4d2;1. 获取输入&…

俄罗斯方块——C语言实践(Dev-Cpp)

目录 1、创建项目(尽量不使用中文路径) 2、项目复制 3、项目配置 ​1、调整编译器 2、在配置窗口选择参数标签 3、添加头文件路径和库文件路径 4、代码实现 4.1、main.c 4.2、draw.h 4.3、draw.c 4.4、shape.h 4.5、shape.c 4.6、board.h 4.7、board.c 4.8、cont…

iOS - TestFlight使用

做的项目需要给外部人员演示&#xff0c;但是不方便获取对方设备的UDID&#xff0c;于是采用TestFlight 的方式邀请外部测试人员的方式给对方安装测试App&#xff0c;如果方便获取对方设备的UDID&#xff0c;可以使用蒲公英 1.在Xcode中Archive完成后上传App Store Connect之前…

数据结构(2):LinkedList和链表[2]

我们在上一篇文章中着重讨论了单链表的实现。其中我们要注意单链表进行遍历时一步一步走的思想。那么这篇文章我们将继续讨论链表的更多内容&#xff0c;那就让我们开始吧。 1.经典单链表算法题 我们将通过几个经典的题对单链表进行进一步的认识。 (1)反转链表 206. 反转链…

clip论文阅读(Learning Transferable Visual Models From Natural Language Supervision)

目录 摘要训练pre-train model的过程将pre-train model应用于下游任务应用&#xff08;待更新&#xff09; 论文/项目地址&#xff1a;https://github.com/OpenAI/CLIP 提供了clip的pre-trained model的权重&#xff0c;也可安装使用pre-trained model 摘要 使用标签标注的图…

C++过生日(我给我自己做的生日礼物)

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &#x1f680;感谢大家点赞&#x1f44d;收藏⭐评论✍ 引言…

电脑开机速度慢怎么解决?

电脑开机速度慢怎么解决&#xff1f;电脑开机速度慢的原因可以是多方面的&#xff0c;以下是一些常见的原因&#xff1a; 启动项过多&#xff1a; 许多软件在系统启动时会自动启动&#xff0c;导致启动项过多&#xff0c;从而延长了开机时间。过时的驱动程序&#xff1a; 设备…

wpf触发与模板的使用示例:批量生产工具

批量生产工具 <Window x:Class"WpfM20UpdateFW.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expressio…

【Kubernetes】常见面试题汇总(十五)

目录 44.简述 Kubernetes RBAC 及其特点&#xff08;优势&#xff09;&#xff1f; 45.简述 Kubernetes Secret 作用&#xff1f; 46.简述 Kubernetes Secret 有哪些使用方式&#xff1f; 47.简述 Kubernetes PodSecurityPolicy 机制&#xff1f; 44.简述 Kubernetes RBAC 及…

基于Python实现一个庆祝中秋节的小程序

功能包括&#xff1a; 使用复杂的库来计算农历日期&#xff1a;可以使用 lunarcalendar 库来计算农历日期。提供更多的祝福语&#xff1a;可以通过随机选择祝福语来增加趣味性。加入图形用户界面 (GUI)&#xff1a;可以使用 tkinter 库来创建一个简单的图形用户界面。 我们可…

2024年Java后端学习路线

思维导图&#xff1a; 必备知识&#xff1a; Java基础 JavaWeb 数据库&#xff1a;MySql&#xff0c;Redis 开发中间件&#xff1a;Maven &#xff0c;Git &#xff0c;Docker&#xff0c;RabbitMQ 开发框架&#xff1a;SSM&#xff0c;spring boot&#xff0c;mybatis-plus、s…