接口常量有什么用?

时间:2010-04-17 19:00:04

标签: java interface constants

我正在学习Java,并且发现接口可以包含公共静态和最终的字段。到目前为止,我还没有看到这些例子。这些接口常量的一些用例有哪些,我可以在Java标准库中看到一些吗?

11 个答案:

答案 0 :(得分:165)

将静态成员放入接口(并实现该接口)是一种不好的做法,甚至还有一个名称,常量接口反模式,请参阅{{ 3}},第17项:

  

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

     

java平台库中有几个常量接口,例如java.io.ObjectStreamConstants。这些接口应该被视为异常和   不应该被模仿。

为了避免常量接口的一些缺陷(因为你不能阻止人们实现它),应该首选一个带私有构造函数的正确类(例如从Effective Java借来的):

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

要访问常量而不必完全限定它们(即不必使用类名称作为前缀),请使用Wikipedia(自Java 5开始):

import static Constants.PLANCK_CONSTANT;
import static Constants.PI;

public class Calculations {

    public double getReducedPlanckConstant() {
        return PLANCK_CONSTANT / (2 * PI);
    }
}

答案 1 :(得分:9)

  

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

无论是谁,他都可以根据需要继续有效地实施不良习惯和做法来编造这个假设,无论他/她是谁。该假设是基于促进不良软件设计习惯的有效性。

我在这里写了一个反驳这个假设的反驳:What is the best way to implement constants in Java?解释了这个假设的无根据。

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

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

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

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

  • 解决根本问题。

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

根本问题

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

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

组织信息存在两到三个重大障碍。

  1. 缺乏对数据模型需求的认识和#34;规范化"。

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

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

  4. 使用接口常量是一种很好的做法。

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

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

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

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

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

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

    Enum常量的使用实际上是可怕的实践。

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

    特别是因为不鼓励您对参数进行规范化和组件化,所以会错误地认为混合到Enum包中的参数属于同一维度。

    常量是API合约

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

    因此,接口是实现常量的完美方式。合同。

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

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

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

    不要放置限制性法令来保护导致未收集/杂散参数泄漏到API中的假定不良行为。解决根本问题,而不是将责任归咎于Interface Constants。

    不使用IDE是不好的做法

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

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

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

    OSGI就是这样一个框架。对于Interface Constants的判决也是如此。

    因此得出结论性答案......

    接口常量是一种有效且高效的方式,可以放入合同设计良好且规范化的数据模型组件中。

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

答案 2 :(得分:7)

Joshua Bloch,“Effective Java - Programming Language Guide”:

  

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

答案 3 :(得分:3)

如果您具有将在实现接口的类中使用的公共常量,它们将非常有用。

这是一个例子: http://www.javapractices.com/topic/TopicAction.do?Id=32

但请注意,建议的做法是在接口中使用静态导入而不是常量。以下是参考:http://www.javapractices.com/topic/TopicAction.do?Id=195

答案 4 :(得分:2)

有些答案非常合理。

但我对这个问题有一些想法。 (可能是错的)

在我看来,接口中的字段不应该是整个项目的常量,它们只是接口的手段,接口扩展它,以及实现这些接口或与它们有密切关系的类。它们应该在一定的范围内使用,而不是全球性的。

答案 5 :(得分:2)

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

为什么要使用接口常量?

只需比较一下:

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

vs

public interface Constants {

    public double PI = 3.14159;
    public double PLANCK_CONSTANT = 6.62606896e-34;
}

用法相同。更少的代码。

不良练习?

我认为@Pascal Thivent的答案强调的错误,这是我的说法:

  

将静态成员放入接口(并实现该接口)是一个坏习惯。

Effective Java中的引言假设常量接口由其他人实现,我认为这不会(也不会)发生。

创建名为Constants之类的常量接口时,任何人都不应实现。 (尽管在技术上可行,但这是这里唯一的问题)

在标准库中不会发生

标准库不能承担任何可能的滥用设计,因此您根本看不到任何设计。

但是,对于普通开发人员的日常项目而言,使用常量接口要容易得多,因为您无需担心staticfinal,{{1} }等,并且不会引起任何不良的设计问题。我唯一想到的缺点是它仍然具有“接口”的名称,仅此而已。

无休止的辩论

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

答案 6 :(得分:1)

javax.swing.SwingConstants接口是获得在swing类中使用的静态字段的示例。这使您可以轻松使用

之类的东西
  • this.add(LINE_START, swingcomponent);
  • this.add(this.LINE_START, swingcomponent);
  • this.add(SwingComponents.LINE_START, swingcomponent);

但是这个界面没有方法......

答案 7 :(得分:1)

我遇到了这个问题,并认为我会添加一些未提及的内容。一般来说,我同意Pascal的回答here。但是,我不认为接口上的常量“始终”是反模式。

例如,如果您定义的常量是合同的一部分 那个界面,我认为界面是常量的好地方。在某些情况下,它不适合私下验证您的参数,而不会将合同暴露给您的实现用户。如果没有面向公众的合同,用户只能猜测您的验证内容,而不是反编译类和阅读代码。

因此,如果您实现了一个接口并且接口具有用于确保合同的常量(例如整数范围),那么您的类的用户可以通过检查常量来确保他们正确使用接口实例在界面本身。如果常量对您的实现或实现是私有的,那么这是不可能的 包装私有或其他东西。

答案 8 :(得分:1)

关于界面的两点:

  • 界面描述了实现该功能的对象子集。 (这是直觉)

  • 接口描述了公共常量,后跟实现该常量的对象

    • 这些通用常量旨在供客户了解以了解有关这些对象的更多信息。
    • 因此,常量接口实际上对于定义全局常量是违反直觉的,因为接口用于描述某些对象,而不是所有对象 / 没有对象(考虑 global 的含义)。

所以我认为,如果 Constants接口不用于全局常量,那么它是可以接受的:

  • 如果这些常用常量具有好名,它们将推荐实施者使用它们(请参见下面的示例的第一点)
  • 如果某个类想与遵循规范的那些类同步,只需implements就可以了(当然,在实现中使用这些公共常量)。

示例:

interface Drawable {

    double GOLDEN_RATIO = 1.618033988;
    double PI = 3.141592653;
    ...

    // methods
    ...
}

public class Circle implements Drawable {
    ...
    public double getCircumference() {
        return 2 * PI * r;
    }
}

void usage() {

    Circle circle = new Circle(radius: 3.0);
    double maxRadius = 5.0;

    if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
        ...
    }

}

在此示例中:

  • Circle implements Drawable开始,您立即知道Circle可能符合Drawable中定义的常量,否则,他们必须选择一个较差的名称,因为好的PI并且GOLDEN_RATIO已被接受!
  • 只有这些Drawable对象符合PI中定义的特定GOLDEN_RATIODrawable,可能存在并非Drawable且精度不同的对象。圆周率和黄金比率。

答案 9 :(得分:-1)

在处理类之间的共享常量时,我​​使用接口常量。

public interface TestConstants
{
    String RootLevelConstant1 = "RootLevelConstant1";

    interface SubGroup1
    {
        String SubGroupConstant1 = "SubGroup1Constant1";
        String SubGroupConstant2 = "SubGroup1Constant2";
    }

    interface SubGroup2
    {
        String SubGroupConstant1 = "SubGroup2Constant1";
        String SubGroupConstant2 = "SubGroup2Constant2";
    }
}

分组是一项巨大的资产,特别是有大量常量。

要使用,您只需将它们链接在一起:

System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);

答案 10 :(得分:-2)

  

字段应在界面中声明,以便更容易   分享并且可以在不引入额外耦合的情况下引用。

来源:Java Developer Tools Coding Style