至少需要指定两个属性的构建器模式

Builder pattern that requires at least two properties to be specified

我正在编写 RequestBuilder class,它将根据以下条件处理查询字符串的创建

由于并非所有条件都是强制性的并且它们之间有很多组合(我数了 7 个,其中只有 4 个应该有效 - 原因见下文),我决定使用构建器模式:

public class RequestBuilder {

    private String category = "";
    private String country = "&country=us";
    private String keywords = "";
    private String page = "";
    private String pageSize = "&pageSize=100";

    public RequestBuilder() {
        
    }

    private String buildQuery() {
        return this.category + this.country + this.keywords + this.page + this.pageSize;
    }
    // the setter methods, which I omitted for readability

但是有个问题。我需要强制用户在构建对象之前至少指定 categorycountrykeywords 中的两个(现在用户甚至没有义务指定一个!)。例如,用户不应该仅通过指定 country 来创建对象。 那么我该如何强制这个要求呢?如果我创建三个构造函数(每个构造函数都有两个参数),我觉得我正在破坏构建器模式,即使还有三个可选属性需要指定。

作为设计师,您需要决定哪些字段是真正需要的。没有“可能需要”这样的东西。要使用构建器模式并强制执行所需参数,请将字段标记为 final 并通过构造函数注入它们:

public class Request {
    // fields
    private final String requiredField;
    private final String optional1;
    private final String optional2;

    private Request(RequestBuilder builder) {
        requiredField = builder.requiredField;
        optional1 = builder.optional1;
        optional2 = builder.optional2;
    }

    // add only getter method to the Request class (builds immutable Request objects)

    public static class RequestBuilder {
        private final String requiredField;
        private String optional1;
        private String optional2;

        public RequestBuilder(String requiredField) {
            this.requiredField = requiredField;
        }

        public RequestBuilder setOptional1(String optional1) {
            this.optional1 = optional1;
            return this;
        }

        public RequestBuilder setOptional2(String optional2) {
            this.optional2 = optional2;
            return this;
        }

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

生成器强制执行必填字段和可选字段。构建器正在构建的对象隐藏了构造函数,因此只能通过构建器访问它。请求对象中的字段都是最终的不变性。

要使用,您需要执行以下操作:

RequestBuilder builder = new RequestBuilder("required");
Request request = builder.setOptional1("foo").setOptional2("bar").build();

或者您可以在调用构建器构造函数后随时调用 build()

更新:

现在解决您的问题....您可以(可能)修改 build() 以检查您拥有多少个“半必填”字段值并将其与字段总数进行比较。对我来说,这是一个黑客。为此,您有两个选择

  1. 对字段数进行硬编码并检查总数中有多少仍然为空。如果未设置的字段数低于某个计数,则抛出一些异常(即 InvalidRequiredFieldCount)。否则,您 return 新实例。为此,您需要在每次调用 setter 方法时增加“计数”。
  2. 使用反射获取字段列表(数组)并使用此字段并使用此字段计数来计算“必填”字段的最小数量。如果未达到最小阈值,则抛出异常;如果达到最小阈值,则 return 一个新的请求实例。
public Request build() throws Exception {
    Request request = new Request(this);
    int count = 0;
    int max = 2;
    Field[] allFields = Request.class.getDeclaredFields();
    for (Field field : allFields) {
        Object o = field.get(request);
        if (o != null) {
            count++;
        }
    }
        
    if (count < 2) {
        throw new Exception("Minimum number of set fields (2) not reached");
    }
        
    return request;
}

这不是很漂亮,但是很管用。如果我 运行 这个:

RequestBuilder builder = new RequestBuilder("required");
Request request = builder.build();

会导致异常:

Exception in thread "main" java.lang.Exception: Minimum number of set fields (2) not reached
    at com.master.oxy.Request$RequestBuilder.build(Request.java:54)
    at com.master.oxy.Request.main(Request.java:63)

但是,如果我设置至少一个可选的,新实例将被 returned。