为什么强烈鼓励使用构建器模式,而不是在 Java 中直接实现流畅的 API?

问题描述

考虑以下构建器模式示例:

import java.util.Objects;

public class Vehicle {
    private final String brand;
    private final int wheels;
    private final int doors;
    private final int maxSpeed;

    private Vehicle(Builder builder) {
        this.brand = Objects.requireNonNull(builder.brand,"brand");
        this.wheels = Objects.requireNonNull(builder.wheels,"wheels");
        this.doors = Objects.requireNonNull(builder.doors,"doors");
        this.maxSpeed = Objects.requireNonNull(builder.maxSpeed,"maxSpeed");
    }

    public static Builder builder() {
        return new Builder();
    }

    public void display() {
        System.out.println("brand = " + getBrand());
        System.out.println("wheels = " + getWheels());
        System.out.println("doors = " + getDoors());
        System.out.println("maxSpeed = " + getMaxSpeed());
    }

    public String getBrand() {
        return brand;
    }

    public int getWheels() {
        return wheels;
    }

    public int getDoors() {
        return doors;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public static class Builder {
        private String brand;
        private Integer wheels;
        private Integer doors;
        private Integer maxSpeed;

        Builder() {
        }

        public Builder setBrand(String brand) {
            this.brand = brand;
            return this;
        }

        public Builder setWheels(int wheels) {
            this.wheels = wheels;
            return this;
        }

        public Builder setDoors(int doors) {
            this.doors = doors;
            return this;
        }

        public Builder setMaxSpeed(int maxSpeed) {
            this.maxSpeed = maxSpeed;
            return this;
        }

        public Builder of(Vehicle vehicle) {
            this.brand = vehicle.brand;
            this.wheels = vehicle.wheels;
            this.doors = vehicle.doors;
            this.maxSpeed = vehicle.maxSpeed;
            return this;
        }

        public Vehicle build() {
            return new Vehicle(this);
        }
    }
}

当我们创建一个 Vehicle 类型的对象时,我们有:

Vehicle vehicle = new Vehicle.Builder()
                .setBrand("Mercedes")
                .setWheels(4)
                .setDoors(4)
                .setMaxSpeed(250)
                .build();

另一方面,可以在类 return this 的每个 setter 中简单地 Vehicle,例如:

public class Vehicle {
    private final String brand;
    private final int wheels;
    private final int doors;
    private final int maxSpeed;

    private Vehicle(String brand,int wheels,int doors,int maxSpeed){
        this.brand = brand;
        this.wheels = wheels;
        this.doors = doors;
        this.maxSpeed = maxSpeed;
    }

    public Vehicle() {
    }

    public String getBrand() {
        return brand;
    }

    public int getWheels() {
        return wheels;
    }

    public int getDoors() {
        return doors;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public Vehicle setBrand(String brand) {
        this.brand = brand;
        return this;
    }

    public Vehicle setWheels(int wheels) {
        this.wheels = wheels;
        return this;
    }

    public Vehicle setDoors(int doors) {
        this.doors = doors;
        return this;
    }

    public Vehicle setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
        return this;
    }

    public void display() {
        System.out.println("brand = " + getBrand());
        System.out.println("wheels = " + getWheels());
        System.out.println("doors = " + getDoors());
        System.out.println("maxSpeed = " + getMaxSpeed());
    }
}

我们可以通过以下方式创建一个 Vehicle 类型的对象:

Vehicle vehicle = new Vehicle();
vehicle.setBrand("Mercedes")
       .setDoors(4)
       .setMaxSpeed(250);

在我看来,第二种方法比传统的构建器模式生成代码更少。尽管如此,我知道许多库使用构建器模式来代替。那么,与第二种方法相比,构建器模式的优点是什么?第二种方法实际上不那么复杂?

解决方法

与 fluent api 相比,构建器模式的一些好处:

  1. Builder 不仅可以返回 Vehicle 类,还可以返回 SomeClass 扩展 Vehicle
  2. 您可以将自定义复杂逻辑添加到构建方法中(验证、切换实现等)
  3. 没有必要的属性就不能创建 Vehicle

但是如果您不需要这些好处,那么使用您的方法绝对是正常的。一些图书馆使用它