构建器模式验证 - 有效的Java

Abh*_*hra 7 java design-patterns builder effective-java

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

在将参数从构建器复制到对象之后检查它们并在对象字段而不是构建器字段(项目39)上检查它们是至关重要的.如果违反了任何不变量,则构建方法应抛出IllegalStateException(Item 60).

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

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

das*_*ght 11

对象验证是使用构建器创建对象的不可或缺的一部分.虽然您可以使用单独的例程进行验证,但不需要进行此类分离:验证代码可以是执行构建的函数的一部分.换句话说,你可以做到这一点

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

或这个:

TargetObject build() {
    TargetObject res = new TargetObject();
    res.setProperty1();
    res.setProperty2();
    if (...) {
        throw new IllegalStateException();
    }
    return res;
}
Run Code Online (Sandbox Code Playgroud)

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


Kev*_*ede 9

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