在 Java 中更改接口常量的实用替代方法

A practical alternative for changing the constants of an Interface, in Java

假设您有一个包含多个 class 的 Java 项目,其中大多数处理一些常量(您的数据集的属性,应该加载(基于您的数据集)在实验开始时)。

为了能够在整个 classes 中访问这些常量,一个非常合理的选择是将常量作为容器的字段 (object/class/Interface)。然后,为了让您的其他 class 使用容器字段,您有 5 种方法

仅当字段是动态的时:

不管字段是动态的还是静态的(当容器是 class 时)

仅当字段为静态时

前两个选项和最后一个选项迫使您在代码中多次写入容器名称 + '.'。 (例如 container.trainingListSize、container.numberOfUsers、Container.trainingListSize、Container.numberOfUsers、.. .) 我正试图摆脱它;第三个选项迫使你成为一个特殊的 class 的儿子,这有时会与你的程序结构相矛盾。 它仍然只是最后的选择;但不幸的是,在 Java 接口中,接口的常量值是最终的,无法在程序开始时加载属性文件时设置。

看问题(Variables in Interface),看来提问者的情况和我一样;但我还没有找到解决方案。

我认为您需要在软件架构中有明确的意图和关注点分离。您谈论 "constants" 但随后您提到从文件加载它们,所以这些毕竟不是真正的常量。这些更像是配置参数。如果这是正确的,您有多种选择。

您可以将您的配置视为全局变量:在这种情况下,我建议创建一个单例 class 从文件加载变量并提供实用方法来访问它们,例如 MyConfig.someParameter() .请注意,您可以静态导入 MyConfig.* 并因此只需使用 someParameter().

即可访问变量

您可以将您的配置视为其他一些容器或上下文的一部分,在这种情况下,很难拥有您想要的精简语法,但您必须注入 context 和然后从您的代码中调用 context.someParameter() 。我不建议将此上下文 class 作为其他对象的基础 class,因为它肯定违反了关注点分离和 OOP 规则,如果 Foo 不是 Context 它不应该从它延伸。请注意,这基本上是您描述的第一个选项。

我要补充一点,您只能在接口中定义静态和最终的成员。这应该不足为奇,因为 java 不支持多重继承或 "mixins"。这是 Java 语言规范团队经过深思熟虑的选择,我相信这是一个很好的选择。您正在尝试做的事情并不真正符合您可以神奇地扩展并从中获取所有成员的接口的概念,除非您使用 java 8 并定义了依赖于从中读取某些地图的默认方法文件或其他东西,例如

interface Config {
  Map<String, String> getProperties();
  default String someProperty() {
    return getProperties().get("some-prop");
  }
  // ... more utility methods follow
}

上面的接口定义了一堆(只显示了一个)实用方法返回字符串属性(实际上可以是任何值)由字符串键控。在启动时,您可以将地图(例如通过文件读取)注入您的 class(es) 并为您神奇地定义所有这些实用程序方法。

使用这种方法的 class 代码如下所示:

class MyExperiment implements Config {
  private final Map<String, String> props;
  MyExperiment(Map<String, String> props) { this.props = props; }

  void someMethod() {
    // read property from injected configuration
    String someProp = someProperty();
  }
}

这可能会为您节省一些输入,但仍然需要您的 classes 实现 Config 并定义 getProperties() 方法,IMO 违反了关注点分离,应该避免。

Java 的一大好处是,它不提供全局变量或常量。这背后的原因是全球性的东西使每个其他 module/class 都可能依赖于那个东西。这再次使您的设计强耦合且难以维护。

所以你需要做的是首先对你的 variables/constants 进行分组,这样它才有意义。 "Container"显然不是这样一个团体的好名字。尽量不要去寻找变量容器,而是尝试找到一个已经存在的 class,它已经包含支持与您的 variables/constants 相同概念的方法。有关这方面的一个很好的例子,请参见 java.lang.Math。 在您的情况下,这可能是您用于加载数据集的存储库-class。

接下来,您应该调查为什么要尝试从 class 外部访问那些 variables/constants。从其他 classes 访问(大量)variables/constants 通常表明设计不当。尝试根据职责对 class 进行分组,您可能会找到一个解决方案,其中只有那些 variables/constants 只能从它们所在的 class 中访问。

所以基本上,如果你觉得你需要去掉数百次容器名称+'.',你应该寻找一个更好的设计,这要么使容器名称的提及变得更好,要么必要的信息或不需要从其他 classes.

访问那些 variables/constants