Pas*_*ent 176
将静态成员放入接口(并实现该接口)是一种不好的做法,甚至还有一个名称,即Constant Interface Antipattern,参见Effective Java,Item 17:
常量接口模式是接口的不良使用.类在内部使用一些常量是一个实现细节.实现常量接口会导致此实现细节泄漏到类的导出API中.类的用户实现一个常量接口并不重要.事实上,它甚至可能使他们感到困惑.更糟糕的是,它代表了一种承诺:如果在将来的版本中修改了类以便它不再需要使用常量,它仍然必须实现接口以确保二进制兼容性.如果非最终类实现了一个常量接口,那么它的所有子类的命名空间都会受到接口中常量的污染.
java平台库中有几个常量接口,例如
java.io.ObjectStreamConstants
.这些接口应视为异常,不应模拟.
为了避免常量接口的一些缺陷(因为你不能阻止人们实现它),应该首选一个带有私有构造函数的正确类(例如从维基百科借来的):
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
Run Code Online (Sandbox Code Playgroud)
要访问常量而不必完全限定它们(即不必使用类名称作为前缀),请使用静态导入(自Java 5起):
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations {
public double getReducedPlanckConstant() {
return PLANCK_CONSTANT / (2 * PI);
}
}
Run Code Online (Sandbox Code Playgroud)
" 常量接口模式是接口使用不当 "
无论是谁,他都是根据需要继续有效地实施坏习惯和习惯而炮制这个假设的人.该假设基于促进不良软件设计习惯的有效性.
我在这里针对这个假设写了一个回应反驳:在Java中实现常量的最佳方法是什么?解释这个假设的无根据.
10年来,这个问题一直悬而未决,直到我在发布我的理由后2小时内关闭了这个假设,从而暴露了UNWILLINGness以供那些坚持这种被误导的假设的人辩论.
这些是我对假设所表达的观点
持有这一假设的基础是需要方法和限制性规则来应对不良软件习惯和方法的影响.
情绪的支持者" 不断的界面模式是界面的不良使用"除了需要应对那些不良习惯和习惯的影响之外,无法提供任何其他原因.
解决根本问题.
然后,为什么不充分利用并利用Java语言结构的每个语言特性以方便您自己.不需要夹克.为什么要制定规则来阻止你的无效生活方式来歧视和判断更有效的生活方式?
是信息组织.在设计或补充流程解决方案之前,应首先了解调解流程的信息,以及所谓的信息行为以及所谓的业务规则.几十年前,这种信息组织方法被称为数据规范化.
然后,只有解决方案的工程设计才有可能,因为将解决方案组件的粒度和模块性与信息组件的粒度和模块性相结合是最佳策略.
组织信息有两到三个重大障碍.
缺乏对数据模型"规范化"需求的认识.
EF Codd关于数据规范化的陈述存在缺陷,缺陷和含糊不清.
伪装成敏捷工程的最新时尚是错误的观念,即人们不应该计划和调整模块的组织,因为你可以随心所欲地进行重构.在不受未来发现阻碍的情况下,重构和持续变化被用作借口.然后,过程信息行为的基本发现是通过使用会计技巧来延迟利润和组合,因此现在认为不需要基本知识及其处理.
不要仅仅因为你喜欢你的特殊的肇事逃逸编程习惯而制定规则或发布任何法令.
不要禁止拥有枪支,因为有些人不知道如何处理枪支或者容易滥用枪支.
如果您编写的规则用于编程新手无法专业编码并且您自己算在其中,那么请说 - 不要声明您的fatwa适用于正确规范化的数据模型.
我不在乎开国元勋们对美国宪法的初衷.我不关心不成文的未经编纂的意图.我只关心书面宪法中的文字编纂,以及如何利用它们来促进社会的有效运作.
我只关心Java语言/平台规范允许的内容,我打算充分利用它们,为我提供一种高效,有效地表达我的软件解决方案的媒介.不需要夹克.
它需要编写额外的代码来将参数映射到值.事实上,Java的创始人没有提供参数值映射而没有编写映射代码演示Enum Constants就像无意中使用Java语言一样.
特别是因为不鼓励您对参数进行标准化和组件化,因此混淆到Enum包中的参数属于同一维度会产生错误的印象.
别忘了.如果您设计并规范化了数据模型,并且它们包含常量,那么这些常量就是契约.如果你没有规范化你的数据模型,那么你应该遵循如何练习限制性编码来应对这种坏习惯的问题.
因此,Interfaces是实现常量契约的完美方式.
对.任何人都可能无意中无意中实现了任何接口.没有什么能阻挡这些无意的程序员.
不要设置限制性法令来保护假定的错误做法,这些做法会导致未收缩/杂散参数泄漏到API中.解决基本问题,而不是将责任归咎于接口常量.
一个正常运作和有效的程序员不能证明她能在水下停留多长时间,她能在多远的高温或潮湿的雷暴中走路.她将使用像汽车或公共汽车这样的高效工具,或者至少骑自行车,每天带她行驶10英里.
不要仅仅因为你对无IDE编程有深奥的禁欲主义的痴迷而对其他程序员施加限制.
OSGI就是这样一个框架.针对接口常量的法令也是如此.
接口常量是放入合同设计良好且规范化的数据模型组件的有效且高效的方法.
嵌套在类文件中的适当命名的私有接口中的接口常量也是将所有私有常量分组而不是将它们分散到整个文件中的好习惯.
我几次遇到这个老问题,被接受的答案仍然使我感到困惑。经过深思熟虑,我认为这个问题可以进一步澄清。
只需比较一下:
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
Run Code Online (Sandbox Code Playgroud)
与
public interface Constants {
public double PI = 3.14159;
public double PLANCK_CONSTANT = 6.62606896e-34;
}
Run Code Online (Sandbox Code Playgroud)
用法相同。更少的代码。
我认为@Pascal Thivent的答案强调的错误,这是我的说法:
将静态成员放入接口(并实现该接口)是一种不好的做法。
有效Java中的引言假设常量接口由其他人实现,我认为不应(也不会)发生这种情况。
当您创建名为的常量接口时Constants
,任何人都不应实现。(尽管在技术上可行,但这是这里唯一的问题)
标准库不能承担任何可能的滥用设计,因此您不会在其中看到任何东西。
然而,对于普通开发人员的日常项目,使用常量接口是一个容易得多,因为你不必操心static
,final
,empty constructor
等,并不会造成任何不良的设计问题。我唯一想到的缺点是它仍然具有“接口”的名称,仅此而已。
最后,我认为每个人都只是在引用书本,并为自己的立场提供意见和理由。我也不例外。也许决定仍然取决于每个项目的开发人员。如果您感到舒适,请继续使用它。我们能做的最好的事情就是在整个项目中保持一致。
Joshua Bloch,"有效的Java - 编程语言指南":
常量接口模式是接口的不良使用.类在内部使用一些常量是一个实现细节.实现常量接口会导致此实现细节泄漏到类的导出API中.类的用户实现一个常量接口并不重要.事实上,它甚至可能使他们感到困惑.更糟糕的是,它代表了一种承诺:如果在将来的版本中修改了类以便它不再需要使用常量,它仍然必须实现接口以确保二进制兼容性.如果非最终类实现了一个常量接口,那么它的所有子类的命名空间都会受到接口中常量的污染.