如何在Java字段中设置基数?

如何在Java字段中设置基数?,java,Java,让我们假设我们有以下类: public class MyClass{ List<String> list; void method() { } } 公共类MyClass{ 名单; void方法(){ } } 这个类的每个对象都有一个字符串列表,但是如果我们想设置基数呢?例如,我想强制该类在该列表中至少有两个字符串 是否有一种通用模式来表示字段的基数?一种方法是为字段使用不同的类型。现在它有了类型List,这是一个可以包含0个或更多元素的集合。您可以将其更

让我们假设我们有以下类:

public class MyClass{
    List<String> list;

    void method() {
    }
}
公共类MyClass{
名单;
void方法(){
}
}
这个类的每个对象都有一个字符串列表,但是如果我们想设置基数呢?例如,我想强制该类在该列表中至少有两个字符串


是否有一种通用模式来表示字段的基数?

一种方法是为字段使用不同的类型。现在它有了类型
List
,这是一个可以包含0个或更多元素的集合。您可以将其更改为表示包含2个或更多元素的列表的类型

您只需通过某种方式确保
列表中至少有2个元素。没有标准或简单的方法可以做到这一点

这被称为类的不变量。作为编写类的人,您有责任确保始终保留该不变量。特别是:

  • 您需要记录列表中至少有2个元素的不变量

  • 您需要确保在构造函数完成时,
    列表
    至少包含两个元素。当构造函数完成时,实例应该是“有效的”(在其文档化的不变量为true的意义上)

  • 您需要确保类中的所有代码在处理列表时都遵循不变量-您可以临时使其无效,但必须确保不可能观察到处于无效状态的实例

    在单线程情况下,这仅仅意味着一旦公共方法返回,不变量必须为true(注意,这包括是否发生异常);但是,如果您的代码设计为以多线程方式使用,您还必须确保任何线程都无法在不变量为false的状态下看到您的实例(例如,您可能需要
    同步的
    块,或者确保更新是原子的)

  • 您需要确保类的子类不能使不变量为false;或者清楚地记录,编写子类的人有责任确保不变量保持为真

    在有效的Java2ndEd中有一个很好的条目:“设计并记录继承,否则禁止继承”

  • 您需要确保类外的任何内容都无法访问对列表的引用。例如,您的代码使列表对同一包中的其他类可见-这些类中的任何一个都可以调用instance.list.clear()
,并使您的不变量无效

这是很难绝对防止的——例如,恶意参与者可能会使用反射使不变量无效。您可以避免这种情况,但这是一个权衡识别和阻止此类方法的努力与不变量变为false的实际成本的问题(这在很大程度上取决于如何使用此类)


到目前为止,实施不变量的最简单方法是在不可变类上。如果不可能更改实例的可观察状态,则不可能使不变量无效。然后,您需要担心的是a)确保类是不可变的;b) 确保构造函数返回后,不变量为true。上面的所有其他点都会消失。

您可以在构造函数中使用var args

public MyClass(String s1, String s2, String... rest){
}
是否存在表示字段基数的通用模式

显然,您可以在对象本身或元级别使用整数字段表示基数。但如果你不能强制执行,那就没什么帮助了

这方面没有一般模式@安迪·特纳(Andy Turner)的回答很好地总结了执行基数的备选方案。我只想补充两点:

  • 试图通过静态类型强制执行基数约束不太可能奏效。Java类型系统不够丰富,无法以令人愉快的方式完成此任务1

  • 构造具有具有最小基数的字段的对象可能很棘手,尤其是在存在涉及这些字段的潜在循环的情况下

  • 处理构造的一种方法是将对象的生命周期分为“构造”阶段和“完成”阶段。在施工阶段,放松约束条件,以便分阶段进行施工。在某个时刻,“完成”的开关被“翻转”。此时,1)检查基数约束,2)更改变异操作的行为以防止违反基数的更改

    这可以使用公共构造函数和“翻转开关”的公共方法来实现。或者,您可以使用;e、 g

    • 使构造函数私有化
    • 在建筑时,使用其他私人方式避开基数
    • 检查基数并在
      build()
      方法中翻转开关(需要)
    另一种方法是允许字段低于基数,但仅允许在字段处于该状态时将项添加到字段中。换句话说,这是一种没有明确开关的“翻转开关”方法。缺点是客户端需要测试基数约束是否有效;i、 约束很弱



    1-理论上,您可以实现一个
    listoftwormore
    接口,等等,但这会带来大量新问题。

    然后您只需要确保列表中至少有2个元素。除了在构造函数返回后确保不变量为真之外,没有标准的方法可以做到这一点。有几种使用AOP的方法,尽管我不知道如何使用AOP