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)是一种创建型设计模式,主要用于分步骤构建复杂对象。与工厂模式不同的是,建造者模式允许你逐步地构造对象,并且不同的步骤可以有不同的实现,最终组合成一个复杂的对象。
这个模式尤其适合那些需要在多个步骤中配置或构造对象的场景,例如建造房子、配置计算机、制作汉堡🍔等。而且它可以让代码更加清晰和灵活,因为你可以通过不同的建造者来实现对象的不同变体。
案例:汉堡制作
假设我们有一个汉堡店,他们提供定制汉堡🍔。顾客可以选择面包类型、肉类、蔬菜、酱料等。每个汉堡可以有不同的组合,因此我们使用建造者模式来简化这个复杂的对象创建过程。
建造者模式的核心角色
- 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;
}
}
// 打印出汉堡的详细信息
@Override
public 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;
}
// 输出汉堡详细信息
@Override
public 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 {
@Override
public void buildBun() {
burger.setBun("Sesame Bun");
}
@Override
public void buildPatty() {
burger.setPatty("Beef Patty");
}
@Override
public void buildSauce() {
burger.setSauce("Cheese Sauce");
}
@Override
public void buildVegetables() {
burger.setVegetables("Lettuce");
}
}
// 具体的素食汉堡建造者
public class VeganBurgerBuilder extends BurgerBuilder {
@Override
public void buildBun() {
burger.setBun("Whole Grain Bun");
}
@Override
public void buildPatty() {
burger.setPatty("Vegan Patty");
}
@Override
public void buildSauce() {
burger.setSauce("Mustard Sauce");
}
@Override
public 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();
}
// 静态的内部类 PersonBuilder
public 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);
}
}
@Override
public String toString() {
return "Person(name=" + this.name + ", age=" + this.age + ", address=" + this.address + ")";
}
}
总结
这些 Java 标准库中的类展示了建造者模式在实际开发中的广泛应用。建造者模式通过分步骤地构建复杂对象,提高了代码的灵活性和可读性,避免了冗长的构造函数调用。这使得代码更具扩展性,并且适合于那些对象创建过程中需要多步骤、多参数的场景。