如何使用构建器模式创建 Class 的多个变体?
How to create multiple varieties of a Class using the Builder Pattern?
我的目标是使用构建器模式创建基于产品类别的产品详细信息字段。
无论产品类别如何,这都是基本的 ProductDetails
属性。
int stock; // required
String ships_from; // required
String brand; // optional
计算机类别可能有
String model; // optional
String screen_size; // optional
String warranty_period; // optional
食品类别可能有
String shelf_life; // required
String expiration_date; // optional
这是我使用的基本构建器模式
public class ProductDetails {
// attributes
private ProductDetails(ProductDetailsBuilder builder) {
this.attribute1 = builder.attribute1;
this.attribute2 = builder.attribute2; // and so on.
}
// getters
public static class ProductDetailsBuilder {
// attributes
public ProductDetailsBuilder(//required attributes) {
this.attribute1 = attribute1;
}
// setters
public ProductDetails build() { return new ProductDetails(this); }
}
}
当我尝试将 ProductDetails
class 扩展为 ProductDetails_Computer
或 ProductDetails_Food
class.
时出现问题
public class ProductDetails_Computer extends ProductDetails {
// attributes
private ProductDetails_Computer(ProductDetails_ComputerBuilder builder) {
this.attribute1 = builder.attribute2;
}
// getters
public static class ProductDetails_ComputerBuilder {
// attributes.
// setters
public ProductDetails_Computer build() { return new ProductDetails_Computer(this); }
}
}
我的预期结果:我可以public class ProductDetails_Computer extends ProductDetails
。
我的实际结果:因为 ProductDetails
构造函数是 private/protected,我无法扩展。有些网站禁止使用public构造函数来避免直接初始化,我同意这种做法。
Effective Java 建议在这种情况下使用 构建器的并行层次结构 。
这里是抽象和具体classes的样子:
产品详情(基础摘要class):
abstract public class ProductDetails {
int stock;
String ships_from;
String brand;
// Recursive generics
abstract static class Builder<T extends Builder<T>> {
int stock;
String ships_from;
String brand;
public Builder(int stock, String ships_from) {
this.stock = stock;
this.ships_from = ships_from;
}
// returns the reference of implementation (child class)
T brand(String brand) {
this.brand = brand;
return self();
}
// force implementation to return child class' builder
protected abstract T self();
// force implementation to return itself while holding "Code to interface" practice
abstract ProductDetails build();
}
protected ProductDetails(Builder<?> builder) {
this.stock = builder.stock;
this.ships_from = builder.ships_from;
this.brand = builder.brand;
}
}
实现可能如下所示:
ProductDetails_Computer
public class ProductDetails_Computer extends ProductDetails {
String model;
String screen_size;
String warranty_period;
private ProductDetails_Computer(Builder builder) {
super(builder);
this.model = builder.model;
this.screen_size = builder.screen_size;
this.warranty_period = builder.warranty_period;
}
public static class Builder extends ProductDetails.Builder<Builder> {
String model;
String screen_size;
String warranty_period;
public Builder(int stock, String ships_from) {
super(stock, ships_from);
}
// child class attributes setter
public Builder model(String model) {
this.model = model;
return this;
}
public Builder screen_size(String screen_size) {
this.screen_size = screen_size;
return this;
}
public Builder warranty_period(String warranty_period) {
this.warranty_period = warranty_period;
return this;
}
@Override
protected Builder self() {
return this;
}
@Override
ProductDetails build() {
return new ProductDetails_Computer(this);
}
}
@Override
public String toString() {
return "ProductDetails_Computer [stock= " + stock + ", brand= " + brand + ", model=" + model + ", screen_size="
+ screen_size + ", warranty_period=" + warranty_period + "]";
}
}
测试类
public class TestBuilder {
public static void main(String[] args) {
var computerBuilder = new ProductDetails_Computer.Builder(20, "XYZ");
computerBuilder.brand("Some_brand")
// able to invoke child class methods because of recursive generics
.screen_size("200").model("some_model");
System.out.println(computerBuilder.build().toString());
}
}
输出:
ProductDetails_Computer [stock= 20, brand= Some_brand, model=some_model, screen_size=200, warranty_period=null]
您可以阅读有关递归泛型的内容 。
我的目标是使用构建器模式创建基于产品类别的产品详细信息字段。
无论产品类别如何,这都是基本的 ProductDetails
属性。
int stock; // required
String ships_from; // required
String brand; // optional
计算机类别可能有
String model; // optional
String screen_size; // optional
String warranty_period; // optional
食品类别可能有
String shelf_life; // required
String expiration_date; // optional
这是我使用的基本构建器模式
public class ProductDetails {
// attributes
private ProductDetails(ProductDetailsBuilder builder) {
this.attribute1 = builder.attribute1;
this.attribute2 = builder.attribute2; // and so on.
}
// getters
public static class ProductDetailsBuilder {
// attributes
public ProductDetailsBuilder(//required attributes) {
this.attribute1 = attribute1;
}
// setters
public ProductDetails build() { return new ProductDetails(this); }
}
}
当我尝试将 ProductDetails
class 扩展为 ProductDetails_Computer
或 ProductDetails_Food
class.
public class ProductDetails_Computer extends ProductDetails {
// attributes
private ProductDetails_Computer(ProductDetails_ComputerBuilder builder) {
this.attribute1 = builder.attribute2;
}
// getters
public static class ProductDetails_ComputerBuilder {
// attributes.
// setters
public ProductDetails_Computer build() { return new ProductDetails_Computer(this); }
}
}
我的预期结果:我可以public class ProductDetails_Computer extends ProductDetails
。
我的实际结果:因为 ProductDetails
构造函数是 private/protected,我无法扩展。有些网站禁止使用public构造函数来避免直接初始化,我同意这种做法。
Effective Java 建议在这种情况下使用 构建器的并行层次结构 。
这里是抽象和具体classes的样子:
产品详情(基础摘要class):
abstract public class ProductDetails {
int stock;
String ships_from;
String brand;
// Recursive generics
abstract static class Builder<T extends Builder<T>> {
int stock;
String ships_from;
String brand;
public Builder(int stock, String ships_from) {
this.stock = stock;
this.ships_from = ships_from;
}
// returns the reference of implementation (child class)
T brand(String brand) {
this.brand = brand;
return self();
}
// force implementation to return child class' builder
protected abstract T self();
// force implementation to return itself while holding "Code to interface" practice
abstract ProductDetails build();
}
protected ProductDetails(Builder<?> builder) {
this.stock = builder.stock;
this.ships_from = builder.ships_from;
this.brand = builder.brand;
}
}
实现可能如下所示:
ProductDetails_Computer
public class ProductDetails_Computer extends ProductDetails {
String model;
String screen_size;
String warranty_period;
private ProductDetails_Computer(Builder builder) {
super(builder);
this.model = builder.model;
this.screen_size = builder.screen_size;
this.warranty_period = builder.warranty_period;
}
public static class Builder extends ProductDetails.Builder<Builder> {
String model;
String screen_size;
String warranty_period;
public Builder(int stock, String ships_from) {
super(stock, ships_from);
}
// child class attributes setter
public Builder model(String model) {
this.model = model;
return this;
}
public Builder screen_size(String screen_size) {
this.screen_size = screen_size;
return this;
}
public Builder warranty_period(String warranty_period) {
this.warranty_period = warranty_period;
return this;
}
@Override
protected Builder self() {
return this;
}
@Override
ProductDetails build() {
return new ProductDetails_Computer(this);
}
}
@Override
public String toString() {
return "ProductDetails_Computer [stock= " + stock + ", brand= " + brand + ", model=" + model + ", screen_size="
+ screen_size + ", warranty_period=" + warranty_period + "]";
}
}
测试类
public class TestBuilder {
public static void main(String[] args) {
var computerBuilder = new ProductDetails_Computer.Builder(20, "XYZ");
computerBuilder.brand("Some_brand")
// able to invoke child class methods because of recursive generics
.screen_size("200").model("some_model");
System.out.println(computerBuilder.build().toString());
}
}
输出:
ProductDetails_Computer [stock= 20, brand= Some_brand, model=some_model, screen_size=200, warranty_period=null]
您可以阅读有关递归泛型的内容