假设您需要定义一个类,它所做的只是保存常量。
public static final String SOME_CONST = "SOME_VALUE";
这样做的首选方法是什么?
- 界面
- 抽象类
- 最后一堂课
我应该使用哪一个,为什么?
澄清一些答案:
枚举- 我不会使用枚举,我不会枚举任何东西,只是收集一些彼此不相关的常量。
接口- 我不会将任何类设置为实现接口的类。只想使用接口调用常量,如下所示:ISomeInterface.SOME_CONST
.
假设您需要定义一个类,它所做的只是保存常量。
public static final String SOME_CONST = "SOME_VALUE";
这样做的首选方法是什么?
我应该使用哪一个,为什么?
枚举- 我不会使用枚举,我不会枚举任何东西,只是收集一些彼此不相关的常量。
接口- 我不会将任何类设置为实现接口的类。只想使用接口调用常量,如下所示:ISomeInterface.SOME_CONST
.
使用最终课程。为简单起见,您可以使用静态导入在另一个类中重用您的值
public final class MyValues {
public static final String VALUE1 = "foo";
public static final String VALUE2 = "bar";
}
在另一个班级:
import static MyValues.*
//...
if(variable.equals(VALUE1)){
//...
}
您的澄清说明:“我不会使用枚举,我不会枚举任何东西,只是收集一些彼此不相关的常量。”
如果常量之间根本不相关,为什么要将它们收集在一起?将每个常量放在与其最密切相关的类中。
我的建议(按优先顺序递减):
1)不要这样做。在与它们最相关的实际类中创建常量。拥有一个“常量包”类/接口并没有真正遵循 OO 最佳实践。
我和其他所有人时常忽略#1。如果您要这样做,那么:
2)带有私有构造函数的最终类这至少可以防止任何人通过扩展/实现它以轻松访问常量来滥用您的“常量包”。(我知道你说过你不会这样做 - 但这并不意味着有人在你之后不会这样做)
3)界面这将起作用,但不是我的偏好,在#2 中可能会提到滥用。
一般来说,仅仅因为这些是常量并不意味着你不应该对它们应用正常的 oo 原则。如果只有一个类关心一个常量,那么它应该是私有的并且在那个类中。如果只有测试关心一个常量 - 它应该在测试类中,而不是生产代码中。如果在多个地方定义了一个常量(不仅仅是偶然地相同) - 重构以消除重复。等等 - 像对待方法一样对待它们。
正如 Joshua Bloch 在 Effective Java 中所说:
如果所有常量都相关(如行星名称),则可以使用 Enum,将常量值放在与它们相关的类中(如果您可以访问它们),或者使用不可实例化的实用程序类(定义私有默认构造函数) .
class SomeConstants
{
// Prevents instanciation of myself and my subclasses
private SomeConstants() {}
public final static String TOTO = "toto";
public final static Integer TEN = 10;
//...
}
然后,如前所述,您可以使用静态导入来使用您的常量。
我的首选方法是根本不这样做。当 Java 5 引入类型安全枚举时,常量的时代几乎消失了。甚至在此之前,乔什·布洛赫(Josh Bloch)发布了一个(稍微冗长的)版本,该版本适用于 Java 1.4(及更早版本)。
除非您需要与某些遗留代码的互操作性,否则真的没有理由再使用命名的字符串/整数常量。
只需使用最终课程。
如果您希望能够添加其他值,请使用抽象类。
使用接口没有多大意义,接口应该指定合同。您只想声明一些常量值。
枚举不是这类东西的最佳选择吗?
enum
s很好。IIRC,有效Java(第2版)中的一项具有enum
枚举标准选项的常量,这些选项interface
为任何值实现[Java关键字]。
我的偏好是使用 [Java 关键字]interface
而不是final class
for 常量。你隐含地得到public static final
. 有些人会争辩说,ainterface
允许糟糕的程序员实现它,但是无论你做什么,糟糕的程序员都会编写出糟糕的代码。
哪个更好看?
public final class SomeStuff {
private SomeStuff() {
throw new Error();
}
public static final String SOME_CONST = "Some value or another, I don't know.";
}
或者:
public interface SomeStuff {
String SOME_CONST = "Some value or another, I don't know.";
}
或者 4. 将它们放在包含使用常量的逻辑最多的类中
...对不起,无法抗拒;-)
对我来说最好的方法是enum
:
public enum SomeApiConstants {;
public static final String SOME_CONST = "SOME_VALUE";
//may be in hierarchy
public enum ApiMapping {;
public static final String VERSION = "/version";
public static final String VERSION_LIST = "/list/{type}";
}
}
优点:
java: enum types may not be instantiated
私有构造函数的缺点之一是方法的存在永远无法测试。
枚举的性质概念很好地应用于特定的域类型,将其应用于分散的常量看起来不够好
Enum 的概念是“枚举是密切相关项的集合”。
扩展/实现常量接口是一种不好的做法,很难考虑扩展不可变常量而不是直接引用它的要求。
如果使用像 SonarSource 这样的质量工具,有规则迫使开发人员放弃常量接口,这是一件尴尬的事情,因为很多项目都喜欢常量接口,很少看到“扩展”的事情发生在常量接口上