接口常量有什么用?

unj*_*nj2 114 java interface constants

我正在学习Java,并且发现接口可以有字段,这些字段是public static和final.到目前为止,我还没有看到这些例子.这些接口常量的一些用例有哪些,我可以在Java标准库中看到一些吗?

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)

  • 好的,但如果你有一个不仅用于恒定定义的界面,那该怎么办呢.所以我有一些接口,它由许多类实现,它包含方法声明,但我也想添加一些常见的值,如大小,例如.在这种情况下,这是非常糟糕的模式吗?一般来说,我同意仅为常量创建接口是反模式. (12认同)
  • 否否否.有效Java中的引用与其他内容有关!仅创建常量接口是保存这些常量的类的更好替代方法.有效的java说:"一个类在内部使用一些常量是一个实现细节".但事实并非如此.我们在谈论'全球'常数.谁愿意在没有方法声明的情况下实现接口? (8认同)
  • 这不仅仅是因为有人在一本书中这么说.只要您不实现该接口以获取对这些常量的访问权限,就可以了. (5认同)
  • 我同意ACV。如果常量接口不是导出的API模块的一部分,或者未在任何地方实现,则看不到问题。使用const final类很丑陋:您需要一个私有的构造函数,因为它没有用,所以会使代码混乱。 (5认同)
  • 这个答案没有正确地呈现《Effective Java》一书中的要点,因为它通过将要点放入括号中来“降级”要点:“(并实现该接口)”。相反,它强调接口中常量的要点(除非您实现这样的接口,否则这是可以的)。这通常不是一个糟糕的答案,因为如果你仔细阅读引用的片段,那么你就可以明白“Effective Java”的作者最初的意思。但我发现它具有误导性。在我看来,“以及实现该接口”部分应该用粗体来强调。 (2认同)
  • 我想我们都同意实现一个接口来获取常量是很糟糕的。现在,即使您导入常量,我认为在某些情况下接口仍然(稍微)比类差,因为您不能强制用户静态导入值而不是扩展接口。相反,使用带有私有构造函数的最终类,您可以强制用户做正确的事情。我想这全都与偏好有关:允许用户使用反模式与样板代码(最终类,私有构造函数,需要编写静态最终)。 (2认同)

Ble*_*eek 9

" 常量接口模式是接口使用不当 "

无论是谁,他都是根据需要继续有效地实施坏习惯和习惯而炮制这个假设的人.该假设基于促进不良软件设计习惯的有效性.

我在这里针对这个假设写了一个回应反驳:在Java中实现常量的最佳方法是什么?解释这个假设的无根据.

10年来,这个问题一直悬而未决,直到我在发布我的理由后2小时内关闭了这个假设,从而暴露了UNWILLINGness以供那些坚持这种被误导的假设的人辩论.

这些是我对假设所表达的观点

  • 持有这一假设的基础是需要方法和限制性规则来应对不良软件习惯和方法的影响.

  • 情绪的支持者" 不断的界面模式是界面的不良使用"除了需要应对那些不良习惯和习惯的影响之外,无法提供任何其他原因.

  • 解决根本问题.

  • 然后,为什么不充分利用并利用Java语言结构的每个语言特性以方便您自己.不需要夹克.为什么要制定规则来阻止你的无效生活方式来歧视和判断更有效的生活方式?

根本问题

是信息组织.在设计或补充流程解决方案之前,应首先了解调解流程的信息,以及所谓的信息行为以及所谓的业务规则.几十年前,这种信息组织方法被称为数据规范化.

然后,只有解决方案的工程设计才有可能,因为将解决方案组件的粒度和模块性与信息组件的粒度和模块性相结合是最佳策略.

组织信息有两到三个重大障碍.

  1. 缺乏对数据模型"规范化"需求的认识.

  2. EF Codd关于数据规范化的陈述存在缺陷,缺陷和含糊不清.

  3. 伪装成敏捷工程的最新时尚是错误的观念,即人们不应该计划和调整模块的组织,因为你可以随心所欲地进行重构.在不受未来发现阻碍的情况下,重构和持续变化被用作借口.然后,过程信息行为的基本发现是通过使用会计技巧来延迟利润和组合,因此现在认为不需要基本知识及其处理.

使用接口常量是很好的实践.

不要仅仅因为你喜欢你的特殊的肇事逃逸编程习惯而制定规则或发布任何法令.

不要禁止拥有枪支,因为有些人不知道如何处理枪支或者容易滥用枪支.

如果您编写的规则用于编程新手无法专业编码并且您自己算在其中,那么请说 - 不要声明您的fatwa适用于正确规范化的数据模型.

一个愚蠢的推理 - Java语言的比目鱼不打算以这种方式使用接口吗?

我不在乎开国元勋们对美国宪法的初衷.我不关心不成文的未经编纂的意图.我只关心书面宪法中的文字编纂,以及如何利用它们来促进社会的有效运作.

我只关心Java语言/平台规范允许的内容,我打算充分利用它们,为我提供一种高效,有效地表达我的软件解决方案的媒介.不需要夹克.

使用Enum Constants实际上是可怕的做法.

它需要编写额外的代码来将参数映射到值.事实上,Java的创始人没有提供参数值映射而没有编写映射代码演示Enum Constants就像无意中使用Java语言一样.

特别是因为不鼓励您对参数进行标准化和组件化,因此混淆到Enum包中的参数属于同一维度会产生错误的印象.

常量是API契约

别忘了.如果您设计并规范化了数据模型,并且它们包含常量,那么这些常量就是契约.如果你没有规范化你的数据模型,那么你应该遵循如何练习限制性编码来应对这种坏习惯的问题.

因此,Interfaces是实现常量契约的完美方式.

一个奇怪的假设 - 如果无意中实现了接口该怎么办?

对.任何人都可能无意中无意中实现了任何接口.没有什么能阻挡这些无意的程序员.

设计并规范您的数据模型以防止泄漏

不要设置限制性法令来保护假定的错误做法,这些做法会导致未收缩/杂散参数泄漏到API中.解决基本问题,而不是将责任归咎于接口常量.

不使用IDE是不好的做法

一个正常运作和有效的程序员不能证明她能在水下停留多长时间,她能在多远的高温或潮湿的雷暴中走路.她将使用像汽车或公共汽车这样的高效工具,或者至少骑自行车,每天带她行驶10英里.

不要仅仅因为你对无IDE编程有深奥的禁欲主义的痴迷而对其他程序员施加限制.

一些框架旨在帮助程序员继续有效地养成坏习惯.

OSGI就是这样一个框架.针对接口常量的法令也是如此.

因此,结论性答案......

接口常量是放入合同设计良好且规范化的数据模型组件的有效且高效的方法.

嵌套在类文件中的适当命名的私有接口中的接口常量也是将所有私有常量分组而不是将它们分散到整个文件中的好习惯.

  • 所有的积分都可以在没有开玩笑,讽刺,情绪的情况下完成.Stackoverflow不是博客平台. (21认同)

Nak*_*ura 7

我几次遇到这个老问题,被接受的答案仍然使我感到困惑。经过深思熟虑,我认为这个问题可以进一步澄清。

为什么要使用接口常量?

只需比较一下:

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,任何人都不应实现。(尽管在技术上可行,但这是这里唯一的问题)

它不会在标准库中发生

标准库不能承担任何可能的滥用设计,因此您不会在其中看到任何东西。

然而,对于普通开发人员的日常项目,使用常量接口是一个容易得多,因为你不必操心staticfinalempty constructor等,并不会造成任何不良的设计问题。我唯一想到的缺点是它仍然具有“接口”的名称,仅此而已。

无休止的辩论

最后,我认为每个人都只是在引用书本,并为自己的立场提供意见和理由。我也不例外。也许决定仍然取决于每个项目的开发人员。如果您感到舒适,请继续使用它。我们能做的最好的事情就是在整个项目中保持一致

  • @krozaine 已更新。感谢您的提醒。任何有疑问的人可以参考:“接口中定义的所有常量值都是隐式公共的、静态的和最终的。” - https://docs.oracle.com/javase/tutorial/java/IandI/interfaceDef.html (3认同)

sta*_*ker 6

Joshua Bloch,"有效的Java - 编程语言指南":

常量接口模式是接口的不良使用.类在内部使用一些常量是一个实现细节.实现常量接口会导致此实现细节泄漏到类的导出API中.类的用户实现一个常量接口并不重要.事实上,它甚至可能使他们感到困惑.更糟糕的是,它代表了一种承诺:如果在将来的版本中修改了类以便它不再需要使用常量,它仍然必须实现接口以确保二进制兼容性.如果非最终类实现了一个常量接口,那么它的所有子类的命名空间都会受到接口中常量的污染.

  • 你实际上没有添加任何尚未说过的有价值的内容。 (3认同)
  • 这个答案比使用此引用的其他答案更旧。 (2认同)