我刚读到某个地方有一个带有常见项目常量的界面是不好的做法,也被称为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);
}
}
我很感激任何指导,以帮助我理解这一点。
答案 0 :(得分:30)
反对"常量接口模式"主要是风格。如果符合您的需要,可以使用Java中的常量接口,实际上Java库包含其中的一些(尽管它们被认为是不应该重复的不良示例)。
许多人将常量接口视为"反模式"在Effective Java,2nd Ed中列举。简而言之,不鼓励使用接口的一些原因包括:
命名空间污染。命名常量出现在所有实现类的名称空间及其子类中。
接口应定义类型。在Java中,项目中的大多数主要类型都应该由接口表示。根据其性质,常量接口不定义类型。
import static
的不可实例化的类。将常量声明为类(而不是接口)中的静态最终字段可实现与在接口中声明它们相同的所有目标。这样做不会导致类的命名空间污染。如果需要,可以使用import static
声明在没有限定类名的情况下使用这些常量。
接口应指定行为。接口应该定义接口和实现类之间的契约。实现接口应该说明类可以做什么。常量接口不遵循这种模式。
答案 1 :(得分:21)
我意识到......如果需要,接口可以由个人实现,这为上面指出的问题留下了空间(即命名空间污染,非常规使用,通过公共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 );
}
}
答案 2 :(得分:6)
那不是pattern。它更像是:
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
。该模式使用了一种可见性技巧,但却掩盖了该类的意图。此外,字段 shadowing 可以在没有编译器警告的情况下发生 - 这更可能是因为您看到 all 接口的字段,即使您不全部使用它们。
import static com.foo.Constants.*;
最好能够实现相同的编码方便性,而不会误导成为Constants
的成员。
答案 3 :(得分:1)
我们可以同时使用这两个类(最终与私有构造函数)和接口。
但是由于以下原因,我更喜欢上课:
接口及其实现类应具有 IS A 关系。 例如:“Cat延伸哺乳动物”意味着猫是哺乳动物。如果我们实现在接口中使用的常量,则不适用。
界面应定义类型。
但是现在我们也可以将静态导入与接口一起使用,但实施它的人有可能违反“IS A”关系。
为常量创建一个类(具有以下属性)并使其成为:
PS :复制用过的示例
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 );
}
}