如何使用构建器模式创建 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_ComputerProductDetails_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]

您可以阅读有关递归泛型的内容