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

🎯 设计模式专栏,持续更新中, 欢迎订阅:JAVA实现设计模式

🛠️ 希望小伙伴们一键三连,有问题私信都会回复,或者在评论区直接发言

Java实现建造者模式(Builder Pattern)

文章目录

  • [Java实现建造者模式(Builder Pattern)](#Java实现建造者模式(Builder Pattern))

建造者模式 (Builder Pattern)是一种创建型设计模式,主要用于分步骤 构建复杂对象。与工厂模式不同的是,建造者模式允许你逐步地构造对象,并且不同的步骤可以有不同的实现,最终组合成一个复杂的对象。

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

案例:汉堡制作

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

建造者模式的核心角色

  1. Builder(建造者接口/抽象类):定义创建产品对象的各个步骤的接口。
  2. ConcreteBuilder(具体建造者):实现Builder接口,提供步骤的具体实现。
  3. Director(指挥者):负责调用建造步骤,指导建造过程。
  4. Product(产品):最终要创建的复杂对象。

代码实现:汉堡制作 🍔

内部类实现:

Step 1:产品类 Burger
java 复制代码
// 产品类: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
java 复制代码
// 指挥者:负责指导汉堡的制作过程
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:客户端代码
java 复制代码
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
java 复制代码
// 产品类:汉堡
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 类
java 复制代码
// 抽象建造者:定义基本的构建步骤
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 类
java 复制代码
// 具体的芝士汉堡建造者
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
java 复制代码
// 指挥者:负责调用建造者的构建步骤
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:客户端代码
java 复制代码
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 中经常使用的用于操作字符串的类,它们可以逐步构建一个字符串,类似于建造者模式。

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 对象。

java 复制代码
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 注解来简化对象创建。

java 复制代码
import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class Person {
    private String name;
    private int age;
    private String address;
}

通过 @Builder 注解,Lombok 会自动为我们生成一个建造者模式类。接下来我们就可以像这样使用:

java 复制代码
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 类大概是这样:

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

相关推荐
o独酌o几秒前
递归的‘浅’理解
java·开发语言
Book_熬夜!3 分钟前
Python基础(六)——PyEcharts数据可视化初级版
开发语言·python·信息可视化·echarts·数据可视化
无问81712 分钟前
数据结构-排序(冒泡,选择,插入,希尔,快排,归并,堆排)
java·数据结构·排序算法
m0_6312704030 分钟前
高级c语言(五)
c语言·开发语言
customer0833 分钟前
【开源免费】基于SpringBoot+Vue.JS在线文档管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
2401_8582861136 分钟前
53.【C语言】 字符函数和字符串函数(strcmp函数)
c语言·开发语言
Flying_Fish_roe1 小时前
Spring Boot-版本兼容性问题
java·spring boot·后端
程序猿进阶1 小时前
如何在 Visual Studio Code 中反编译具有正确行号的 Java 类?
java·ide·vscode·算法·面试·职场和发展·架构
程序猿练习生1 小时前
C++速通LeetCode中等第5题-无重复字符的最长字串
开发语言·c++·leetcode
slandarer1 小时前
MATLAB | R2024b更新了哪些好玩的东西?
java·数据结构·matlab