10

我有一种情况,我希望特定类型的记录实例只能使用同一包内的单独类中的工厂方法创建。这样做的原因是因为在创建记录之前我需要执行大量的验证。

记录旨在成为其验证字段的哑数据载体,但验证不能在记录的构造函数中进行,因为我们需要访问一些复杂的验证器对象才能实际执行验证。

由于将验证器对象传递给记录构造函数意味着它们将构成记录状态的一部分,这意味着我们不能使用记录构造函数来执行记录的验证。

因此,我将验证提取到它自己的工厂中并编写了类似这样的代码(工厂类和同一包中的记录):

package some.package;

// imports.....

@Component
class SomeRecordFactory {
    private final SomeValidator someValidator;
    private final SomeOtherValidator someOtherValidator;
    // Rest of the fields
    // ....

    // constructor  
    // ....


    public SomeRecord create(...) {
         someValidator.validate(....);
         someOtherValidator.validate(....);
         // .... other validation

         return new SomeRecord(...);
    }
}
package some.package;

public record SomeRecord(...) {
    /* package-private */ SomeRecord {
    }
}

无论出于何种原因,上述内容不适用于 IntelliJ 抱怨:

Compact constructor access level cannot be more restrictive than the record access level (public)

我可以通过使用普通类(它允许单个包私有构造函数)来避免这个问题,但希望更准确地将数据建模为记录。

为什么对记录存在此限制?未来是否有计划取消此限制?

4

2 回答 2

10

问:为什么对记录存在此限制?

JEP 359或 JLS中没有明确说明该决定的理由,但我认为 JEP 的这段摘录暗示了这一点:

“因为记录在语义上声称是其数据的透明载体……”

“透明载体”意味着(对我来说1)记录被设计为具有最小的抽象边界。限制构造函数的访问意味着(对我而言)额外的抽象边界。

此外,我怀疑具有更多限制性访问修饰符的记录构造函数可能会阻碍或使 Java 未来版本中记录的预期用例复杂化。

无论如何,我的看法是,如果你想要这样的花哨的东西,你应该声明一个类而不是一个记录。

1 - 透明与不透明相反,抽象数据类型通常在设计上是不透明的。显然,这只是我对 JEP 作者的意思的看法。


问:有没有计划在未来取消这个限制?

我不知道。没有关于此的(公共)开放 Java 错误或 RFE。

实际上,与该主题相关的所有 JDK 错误都是为了确保 Java 15+ 规范明确了限制。没有迹象表明限制是偶然或疏忽发生的。

于 2020-11-19T02:22:57.873 回答
8

我在琥珀邮件列表( http://mail.openjdk.java.net/pipermail/amber-dev/2020-December.txt)上问了这个问题。

提出了这个问题:

规范构造函数必须具有与记录相同的访问权限的确切原因是什么?

给出的答案是(重点是我的):

记录被命名为元组,它们仅由它们的组件以透明的方式定义,即没有封装。从元组中,您可以访问每个组件的值,并且从所有组件值中,您可以创建一个元组。 这个想法是,在一种方法中,如果您能够看到记录,则可以创建它。因此,规范构造函数与记录本身具有相同的可见性。

因此,存在限制以符合设计目标和事实,即如果有人拥有记录的实例,他们应该能够解构它,然后使用规范构造函数重建它。当然,作为必然结果,这需要规范构造函数具有与记录本身相同的访问权限。

于 2021-05-20T20:53:30.127 回答