构建器模式验证 - 有效 Java

Builder pattern validation - Effective Java

在 Effective Java(第 2 版)的第 2 项中,作者提到了以下关于在使用构建器时对参数施加不变量的内容:

It is critical that they be checked after copying the parameters from the builder to the object, and that they be checked on the object fields rather than the builder fields (Item 39). If any invariants are violated, the build method should throw an IllegalStateException (Item 60).

这是否意味着在构建方法创建目标对象后,应该将其传递给验证例程以进行任何所需的验证?

此外,有人可以解释一下这背后的原因吗?

对象验证是使用构建器创建对象的组成部分。虽然您可以有一个单独的例程来执行验证,但不需要这样的分离:验证代码可以是执行构建的函数的一部分。换句话说,你可以这样做

TargetObject build() {
    TargetObject res = new TargetObject();
    res.setProperty1();
    res.setProperty2();
    validate(res); // This call may throw an exception
    return res;
}

void validate(TargetObject obj) {
    if (...) {
        throw new IllegalStateException();
    }
}

或者这个:

TargetObject build() {
    TargetObject res = new TargetObject();
    res.setProperty1();
    res.setProperty2();
    if (...) {
        throw new IllegalStateException();
    }
    return res;
}

重要的是验证发生在构建目标对象之后,而不是之前。换句话说,您需要验证对象的状态,而不是构建器的状态。

构建器的 build() 方法通常会调用它正在构建的 class 的私有构造函数。这就是构建器通常实现为静态嵌套 classes 的原因,因此它们可以访问私有构造函数。构造函数是进行验证的地方。即使您不使用构建器模式,构造函数也负责确保对象在创建时处于有效状态。并且构造函数应该创建防御性副本(EJ 项目 39)并验证新对象的字段,而不是 构建器的字段,因为在复制字段时构建器可能会发生变异。