生成器模式。重复参数的初始化?
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();
假设我有一个汽车制造商,有模型、颜色和速度等参数:
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();