使用空构造函数强制前置条件

Posted

技术标签:

【中文标题】使用空构造函数强制前置条件【英文标题】:forcing preconditions with empty constructor 【发布时间】:2018-03-28 09:29:04 【问题描述】:

我有几个对象需要能够解析,其中包括球衣。这迫使我显式添加一个空构造函数,因为框架正在使用反射和空构造函数进行实例化。

我看到的问题是我不能强加任何先决条件。以如下代码为例:

public class Model 
    /**
     * 0 < value < 100
     */
    int value;

    public Model()  //The much needed empty constructor

    public Model(int value) 
        if(value < 1 || value > 99)
            throw new IllegalArgumentException("Value must be between 1 and 99 inclusive");
        this.value = value;
    

这里的值确实有一个先决条件,根据使用情况,将其设置为任何默认值可能没有意义(例如,如果 value 是一个必须存在于数据库中的 ID)。但是由于其他框架需要一个空的构造函数,所以可以创建一个 Model 对象,它打破了前置条件,因此是无效的。

所以我有点好奇这通常是如何解决的。有没有办法让空构造函数只为反射调用打开?还是更标准地接受它是错误的并在其中创建一个 isValid 函数,您可以调用该函数以确保前提条件成立?或者可能有一个不同的验证器对象来检查其有效性(以使模型与业务逻辑保持清晰)?

【问题讨论】:

您可以在默认构造函数中为您的“value”变量分配一个默认值。 @zappee 是的,但正如我在代码下所写的那样,拥有默认值并不总是有意义的。例如,如果它是一个外部 ID,它必须匹配一些其他对象 ID,并且创建另一个对象作为默认值似乎真的很糟糕 @munHunger 如果您需要“解析”您的对象,那么它更像是一个 DTO 而不是业务对象,这意味着它不应该实现任何逻辑。将其设为哑对象并在解析为您的真实业务对象时进行验证。 大多数这样的框架都没有强制要求有一个公共的默认 ctor。例如,Java 外部序列化需要一个默认的 ctor,但一个私有的就足够了。反射可以访问私有成员... @munHunger 简化了很多,我会转换我的代码,以便您在某处执行businessModel = parse(modelDTO) 之类的操作。然后将验证放在parse() 逻辑或businessModel 构造函数中。由于businessModel 是理想的 POJO,因此它与框架限制隔离。 【参考方案1】:

您有一种情况,框架迫使您接受最初无效对象的创建。据推测,框架必须使用 setter 使对象在使用之前有效。您可以使用 Builder 来确保只能创建有效的对象。您的框架只知道 Builder,而不知道 Model 本身:

@Resource // or whatever your framework needs
public class ModelBuilder 
    private int value;

    public ModelBuilder() 

    public setValue(int value) 
        if(value < 1 || value > 99)
            throw new IllegalArgumentException("Value must be between 1 and 99 inclusive");
        this.value = value;
    

    public Model build() 
        if (value == 0)
            throw new IllegalStateException("Value must be set before building.");
        return new Model(value);


public class Model 
    /**
     * 0 < value < 100
     */
    private final int value;

    public Model(int value) 
        if(value < 1 || value > 99)
            throw new IllegalArgumentException("Value must be between 1 and 99 inclusive");
        this.value = value;
    

    // Other methods...

【讨论】:

以上是关于使用空构造函数强制前置条件的主要内容,如果未能解决你的问题,请参考以下文章

软件构造第三章第二节 设计规约

类中移动构造函数的位置/顺序很重要?与移动构造函数结合使用的模板化强制转换运算符

防止 Proguard 删除片段的空构造函数

在 VS Code 中强制使用多行 typescript 构造函数

如何强制函数参数为相同类型并且不允许使用类型构造函数匹配给定类型?

defrecord 构造函数中未强制执行类型提示