生成器模式。重复参数的初始化?

Builder pattern. Initialization of duplicate parameters?

假设我有一个汽车制造商,有模型、颜色和速度等参数:

 public class Car {

    private String model;
    private int color;
    private int speed;

    public Car(String model, int color, int speed) {
        this.model = model;
        this.color = color;
        this.speed = speed;
    }

    //..Getters

    public static class Builder {
        private String model;
        private int color;
        private int speed;

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

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

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

        public Car build() {
            return new Car(model, color, speed);
        }
    }
}

我这样造车:

    Car car1 = new Car.Builder()
            .model("Audi")
            .color(Color.RED.getRGB())
            .speed(200)
            .build();
    Car car2 = new Car.Builder()
            .model("Audi")
            .color(Color.RED.getRGB())
            .speed(350)
            .build();
    Car car3 = new Car.Builder()
            .model("Audi")
            .color(Color.RED.getRGB())
            .speed(175)
            .build();

如您所见,我有一些参数必须不断复制。我希望能够基于一些现有的空白来制造新车,如下所示:

    Car car1 = new Car.Builder()
            .initFrom(redAudi)
            .speed(200)
            .build();
    Car car2 = new Car.Builder()
            .initFrom(redAudi)
            .speed(350)
            .build();
    Car car3 = new Car.Builder()
            .initFrom(redAudi)
            .speed(175)
            .build();
}

是否有为此提供的模板?

将方法 initFrom(Car) 添加到您的 Builder class,它调用给定 Car 实例的所有 getter 并使用 return 初始化其参数值。以后调用 Builder 的方法可能会用当时正确的值覆盖这些值。

接下来您可以引入一个 TemplateCar class 作为 class 到 Car 的新父级,它允许使用不完整的参数集进行构建,并且具有自己的Builder(当然,那你需要把上面说的方法改成initFrom(TemplateCar))。

这就是您要求“模板”时的意思吗?

这是一个常见问题。本质上,您需要公开一个 asBuilder()。此实例方法获得一个 构建器,该构建器使用传递的实例 .

的值进行初始化
Car existingCar = Car.builder()......build() ;

//new car with same props as existing but the speed
Car existingCarButFaster = existingCar.asBuilder()
                           .speed(existingCar.speed * 2)
                           .build();

asBuilder() 的实现应该很简单。

此外,您似乎生成了很多样板文件。如果使用代码生成器连接代码库对您来说不是问题,您可以使用绝大多数项目使用的 Lombok 库。

    /**
     * If true, generate an instance method to obtain a builder that is initialized with the values of this instance
     * Legal only if {@code @Builder} is used on a constructor, on the type itself, or on a static method that returns
     * an instance of the declaring type.
     * 
     * @return Whether to generate a {@code toBuilder()} method.
     */
    boolean toBuilder() default false;

感谢您的回答!我决定采用@tquadrat 的解决方案,但对其进行了扩展。我决定为初始化构建器的 类 添加一个接口。

Car.java

public class Car {

private final String model;
private final int color;
private final int speed;

public Car(String model, int color, int speed) {
    this.model = model;
    this.color = color;
    this.speed = speed;
}

//..Getters

public static class Builder {
    private String model;
    private int color;
    private int speed;

    public Builder initFrom(@NotNull CarBuilderInitializer initializer) {
        Builder builder = initializer.initBuilder(this);
        this.model = builder.getModel();
        this.color = builder.getColor();
        this.speed = builder.getSpeed();
        return this;
    }

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

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

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

    public Car build() {
        return new Car(model, color, speed);
    }
}}

CarBuilderInitializer.java

    public interface CarBuilderInitializer {
    Car.Builder initBuilder(Car.Builder builder);
}

你的自定义构建器Car.java

 public class YourCustomBuilderCar implements CarBuilderInitializer {
    @Override
    public  initBuilder(@NotNull Car.Builder builder) {
        return builder
                .model("Audi");
                .color(Color.RED);
    }
}

客户端代码: 汽车 car1 = new Car.Builder() .initFrom(新的 YourCustomBuilderCar()) .speed(200) .build();