恒定界面反模式澄清

我刚刚读到某个地方有一个带有常见项目常量的接口是不好的做法,也被称为Constant Interface Anti-Pattern 。 如果我理解正确,提供的原因是,一旦实现,该类将公开这些常量。

好吧,我不明白首先需要“实施”。 是不是可以直接使用这些静态常量? 那么为什么我必须经历import static的麻烦,当我可以做类似的事情:

 interface Constants { public static final int FOO_1 = 1; public static final int FOO_2 = 2; } public class Test { public static void main(String[] args) { System.out.println(Constants.FOO_2); } } 

我很感激任何指导,以帮助我理解这一点。

反对“常量接口模式”的论据主要是风格。 如果符合您的需要,您可以在Java中使用常量接口,实际上Java库包含其中的一些(尽管它们被认为是不应该重复的不良示例)。

许多人认为常量接口是“反模式”的原因在Effective Java,2nd Ed中列举。 简而言之,不鼓励使用接口的一些原因包括:

  • 命名空间污染。 命名常量出现在所有实现类的名称空间及其子类中。

  • 接口应该定义类型。 在Java中,项目中的大多数主要类型都应该由接口表示。 根据其性质,常量接口不定义类型。

  • import static不可实例化的类。 将常量声明为类(而不是接口)中的静态最终字段可实现与在接口中声明它们相同的所有目标。 这样做不会导致类的命名空间污染。 如果需要,可以使用import static声明在没有限定类名的情况下使用这些常量。

  • 接口应指定行为。 接口应该定义接口和实现类之间的契约。 实现接口应该说明类可以做什么。 常量接口不遵循此模式。

我意识到……如果需要,接口可以由个人实现,这为上面提到的问题留下了空间(即命名空间污染,非常规使用,通过公共API暴露)。 因此,最好完全阻止完全实现接口的能力。 因此,使用私有构造函数创建一个final类更合适,这样就无法实例化/扩展它。

 public final class Constants { // to restrict instantiation private Constants() {} public static final double PI = 3.14159; public static final double PLANCK_CONSTANT = 6.62606896e-34; } 

…并将其与import static结合使用。

 import static Constants.PLANCK_CONSTANT; import static Constants.PI; public class Calculations { public double getReducedPlanckConstant() { return PLANCK_CONSTANT / ( 2 * PI ); } } 

那不是那种模式 。 它更像是:

 interface Constants { final int FOO_1 = 1; final int FOO_2 = 2; } public class MyClass implements Constants { public static void main( String[] args ) { System.out.println( FOO_2 ); // compiles OK } } 

恕我直言,问题是MyClass “不是” Constants 。 该模式使用了一种可见性技巧,但却掩盖了该类的意图。 此外,字段阴影可以在没有编译器警告的情况下发生 – 这更可能是因为您看到了界面的所有字段,即使您不全部使用它们。

最好import static com.foo.Constants.*; 实现相同的编码方便性,没有误导成为Constants的成员。

我们可以使用class(带有私有构造函数的final)和Interface。 但是由于以下原因,我更喜欢上课:

  1. 接口及其实现类应具有“IS A”关系。 例如:“猫延伸哺乳动物”意味着猫是哺乳动物。 如果我们实现在接口中使用的常量,则不适用。

  2. 接口应该定义一个类型。

  3. 但是现在我们也可以使用带有Interface的静态导入,但实施它的人有可能违反“IS A”关系。

为常量创建一个类并使其成为:1。FINAL – 因此它不能被其他类inheritance。 2.只有一个私有的构造函数: – 因此无法实例化。 服务于所有目的。

抱歉,复制使用过的示例

 public final class Constants // so it cannot be inherited { private Constants() {} // to restrict instantiation public static final double PI = 3.14159; public static final double PLANCK_CONSTANT = 6.62606896e-34; } 

现在用法:

 import static Constants.PLANCK_CONSTANT; import static Constants.PI; public class Calculations { public double getReducedPlanckConstant() { return PLANCK_CONSTANT / ( 2 * PI ); } }