在他的书Effective Java中,Joshua Bloch建议不要使用接口来保持常量,
常量接口模式是接口的不良使用。类在内部使用一些常量是一个实现细节。实现常量接口会导致此实现细节泄漏到类的导出API中。类的用户实现一个常量接口并不重要。事实上,它甚至可能使他们感到困惑。更糟糕的是,它代表了一种承诺:如果在将来的版本中修改了类以便它不再需要使用这些元素,它仍然必须实现接口以确保二进制兼容性。如果非最终类实现了一个常量接口,那么它的所有子类的命名空间都会受到接口中常量的污染。
他的推理对我来说很有意义,而且每当提出这个问题时它似乎都是流行的逻辑,但它忽略了在接口中存储常量然后没有实现它们。
例如,
public interface SomeInterface {
public static final String FOO = "example";
}
public class SomeOtherClass {
//notice that this class does not implement anything
public void foo() {
thisIsJustAnExample("Designed to be short", SomeInteface.FOO);
}
}
我与一直使用此方法的人合作。我倾向于使用带有私有构造函数的类来保存我的常量,但我已经开始以这种方式使用接口来保持代码的一致性。 有没有理由不以我上面概述的方式使用接口?
基本上它是一个简短的手,可以防止你必须私有一个类,因为接口无法初始化。
答案 0 :(得分:5)
我想它确实起了作用,但正如朋友曾经说过的那样:“你可以尝试用章鱼拖地板;它可能会完成工作,但它不是正确的工具”。
存在用于指定合同的接口,然后由类实现。当我看到一个接口时,我假设有一些实现它的类。所以我倾向于说这是滥用接口的一个例子,而不是使用它们,只是因为我不认为接口的使用方式是这样的。
我想我不明白为什么这些价值观首先是公开的,如果它们只是在一个班级私下使用。为什么不把它们移到课堂上?现在,如果这些值将由一堆类使用,那么为什么不创建enum
?我见过的另一种模式是一个只保存公共常量的类。这与您描述的模式类似。但是,这个课程可以成为最终的,以便不能扩展;没有什么可以阻止开发人员实现你的界面。在这些情况下,我只是倾向于使用enum
。
<强>更新强>
这将是对评论的回应,但随后它变得很长。创建一个只保存一个值的界面更加浪费! :)你应该使用私有常量。虽然将不相关的值放入单个枚举中是不好的,但您可以将它们分组到单独的枚举中,或者只是为该类使用私有常量。
此外,如果看起来所有这些类都共享这些不相关的常量(但在类的上下文中有意义),为什么不创建一个抽象类,将这些常量定义为protected
?您所要做的就是扩展此类,您的派生类将可以访问常量。
答案 1 :(得分:3)
我不认为具有私有构造函数的类比使用接口更好。
引用的内容是使用implements ConstantInterface
并非最佳实践,因为此界面成为API的一部分。
但是,您可以使用静态导入或限定名称,例如界面中值SomeInteface.FOO
,以避免此问题。
答案 2 :(得分:2)
无论如何,常数是一件坏事。在一个位置填充一堆字符串表明您的应用程序从一开始就存在设计问题。它不是面向对象的(特别是对于String Constants)会导致脆弱API的开发
如果一个类需要一些静态值,那么它们应该是该类的本地值。如果更多的类需要访问这些值,则应将它们提升为枚举并进行建模。如果你真的坚持要有一个充满常量的类,那么你用private no args构造函数创建一个final类。通过这种方法,您至少可以确保降压停在那里。没有允许实例化,您只能以静态方式访问状态。
这种特殊的反模式有一个严重的问题。没有任何机制可以阻止某人使用你的类来实现这个胭脂常量接口。它实际上是关于解决java的限制,它允许你做非感性的事情。
净出局是它降低了应用程序设计的意义,因为对语言原则的掌握并不存在。当我使用常量接口继承代码时,我会立即猜测所有内容,因为谁知道我会找到其他有趣的黑客。
答案 3 :(得分:0)
为常量创建一个单独的类似乎很愚蠢。这比制作枚举更有意义,唯一的原因是将不相关的常量保存在一个地方只是因为可能它们都碰巧被相同的代码块引用。希望当你考虑将一大堆不相关的东西放在一起并称之为课堂时,你的糟糕气味就会发出警报。
对于接口,只要你没有实现接口,它就不是世界末日(并且JDK有许多实现SwingConstants
的类),但可能有更好的方法依赖你究竟在做什么。
Map<String,String>
的{{1}}来满足更多一般需求Collections.unmodifiableMap
从文件中读取常量并对其进行换行或子类化以防止更改此外,对于静态导入,懒惰的人没有理由通过执行java.util.Properties
来实现一个接口来获取其常量。