通常我们会在应用程序中看到常量文件的需求,它存储要在多个位置共享的常量。在设计应用程序时,我遇到了类似的情况,我们需要在应用程序的多个位置使用各种常量。
我确信,我需要一个单独的文件来存储公共静态常量。但我不太确定将其设为接口还是类。 (枚举不适合我的要求)。所以我有两个选择:
一个接口,例如
package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}
或者
package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}
我的观点是使用接口。我的论点是,由于接口自动将字段设置为 public static 和 final,这将是有利的,以防万一有人错过将它们添加到新常量。它还使代码看起来更简单、更清晰。
此外,简单测试表明相同的接口(字节类)的大小为 209 字节(在 ubuntu 14.04 上),而类(字节类)的大小为 366 字节(在相同的操作系统上)。更小的字节类意味着更少的加载和维护。此外,在加载接口时,JVM 无需担心它为类提供的额外功能(例如方法的重载/动态绑定等),因此加载速度更快。
这看起来不错,但这是反模式的典型案例。尽管使用接口作为常量可能看起来很有帮助,但它会留下一个漏洞,可能会影响以后的应用程序策略。
假设有一个类,它在很大程度上依赖于这些常量。开发人员在编写代码时看到接口名称在整个类中重复出现,例如
package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}
所以,为了 “清理” 他可能想要实现接口的代码,这样他就不需要到处写“packagename.Constants”,所有的常量都可以直接访问。
但是一旦他实现了接口,所有常量就成为他的“合同”的一部分(因为它们是公共的和静态的)。这可能会导致在类的契约中添加非必需的常量部分。这动摇了基本面,并增加了混乱。在 Java 中没有办法阻止接口被类实现。
另一方面,我们可以使类最终化,因此不可扩展。此外,我们可以将构造函数设为私有,因此此类是不可实例化的。由于新类是不可实例化的,因此它永远不会违约。此外,如果在同一个类中多次使用特定常量,开发人员可能会使用静态导入。
因此,一个好的 Constants 类设计应该是:
package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}
静态导入的一个例子是:
package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}
这样的设计问题也称为 Constant Interface Anti-pattern 。