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

时间:2015-04-06 15:23:37

标签: java interface implementation extend static-members

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

为了能够在整个类中访问这些常量,一个非常合理的选择是将常量作为容器(对象/类/接口)的字段。然后,为了让你的其他类利用容器字段,你有5种方法

仅当字段是动态字段时:

  • 将容器传递给处理方法(处理所需常量的方法)
  • 将容器放在方法类(您的方法所在的类)的字段中。

然而,该字段是动态的还是静态的(当容器是一个类时)

  • 通过方法类扩展该字段的容器。

仅当字段是静态的

  • 通过方法类实现该字段的容器。
  • 调用静态字段(Container.field)

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

看问题(Variables in Interface),提问者似乎和我一样;但我找不到解决方案。

2 个答案:

答案 0 :(得分:1)

我认为您需要在软件架构中明确意图并分离关注点。你谈到“常量”,但是你提到从文件加载它们,所以这些并不是真正的常量。这些更像是配置参数。如果这是正确的,你有几个选择。

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

您可以将您的配置视为其他容器或上下文的一部分,在这种情况下,根据需要使用纤薄的语法要困难得多,但您必须注入context然后调用代码中的context.someParameter()。我不建议将此上下文类作为其他对象的基类,因为它肯定违反了关注点分离和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 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();
  }
}

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

答案 1 :(得分:1)

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

所以你需要做的是首先对你的变量/常量进行分组,这样才有意义。 &#34;集装箱&#34;这个团体显然不是一个好名字。尽量不要去变量容器,而是尝试找到一个已经存在的类,它已经拥有支持与变量/常量相同的概念的方法。有关此的一个很好的示例,请参阅java.lang.Math。 在您的情况下,这可能是您用于加载数据集的存储库类。

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

所以基本上,如果你觉得你需要摆脱数百次容器名称+&#39;。&#39;,你应该寻找一个更好的设计,这要么提到容器命名一个好的和必要的信息,或者不必从其他类中访问这些变量/常量。