【问题标题】:Ideal way to organize Java constants组织 Java 常量的理想方式
【发布时间】:2012-03-18 03:04:57
【问题描述】:

我们有一个基于旧 jdk 1.4 的大型项目。我们已将 Web 应用迁移到 JDK 1.6,但代码中仍然存在许多低效做法和不良设计。

在单个 Java 文件中包含 2500 多行代码的巨大 Java 类的主要痛点。像这样的文件太多了。

为了重构我一开始的类,我删除了常量并将常量放在不同的 Constants.java 文件中。但由于整个应用程序中有很多常量,因此常量文件有增长到巨大比例的风险。

对于开发人员采用什么策略来保持代码清洁和可维护性的反馈,我将不胜感激。

【问题讨论】:

  • 单个Constants 类听起来像是一种反模式。根据常量的含义将它们拆分,或者在适当的地方用枚举替换它们。
  • 作为一种预防措施,将电极连接到您的开发人员身上,这会在他们保存文件时以 LOC * 0.01V 的电压对他们进行电击。
  • 您要解决哪些具体问题?只是文件太大的事实?如果是这样,那么重构一切的成本将不值得。
  • 它不仅仅是文件的长度/大小。它违反了每个类以及代表多个合同的类的职责。一个用于存储主页值的 bean 类(一个 Model)也为 html 模板创建和处理缓存结构。这只是一个例子
  • 也许您可以将常量放在内部 static final 类中,这样您就可以将它们组合在一起,然后在您的 IDE 中折叠它们。之后,您可以将这些类从它们所来自的类中分离出来,并将它们实现为具有真正功能的类。

标签: java coding-style constants code-organization


【解决方案1】:

将常量保存在与它们相关的类中,不要觉得有义务提取它们。它可能会清理类的代码,但在文件中混合不相关的常量并不是一种改进。

把相关的东西放在一起

您还可以在可能/有用的情况下将它们转换为 枚举(但这可能需要进行一些重构)。

【讨论】:

  • 但是常量值总是存在重复的风险。例如,表名“user_profile”存储在多个常量中,如 EMPLOYER_USER_PROFILE 和 WEB_USER_PROFILE。等
  • 为什么不能将表名作为常量存储在 DAO 类(该表的类)中,然后从其他类中使用该常量? (它需要将常量声明为公共)
  • @RegMem 您可以使用 checkstyle 和可能的其他静态代码分析器来查找相同的字符串并在重复项上放置警告(或我使用的“信息”标签)。
【解决方案2】:

将所有常量放在一个文件中是一个糟糕的主意!尤其是 uber-Constant 反模式,其中所有常量都在 Interface 中,每个类都必须在 implement 中。周日可怕的 10 种方法!当人们在 Java 之前的 1990 年代早期开始这样做时,这是一个坏主意! 2012年绝对是个坏主意!

这意味着您每次导入此 uber-Constants 文件时都会混合大量不相关的信息并创建不需要的依赖项。一起发生的事情应该放在Enum 或至少在Class 中,将它们用作其方法的参数,以便在更改它们时您知道如何轻松进行影响分析。

想象Color 常量与DaysOfTheWeek 常量与其他业务领域常量混合在一起,在一个文件中将有数百甚至数千个这样的东西。这怎么可能被认为是一个好主意?在每一种非人为的情况下,作为public inner 成员的EnumClass 的一个更好的解决方案。

这也意味着您有一个单一的平面命名空间来尝试创建不冲突的名称,那么它们属于什么以及应该如何使用它们并不明显。这绝不是一种积极的锻炼。

在设计和重构时,您应该始终:

力求高凝聚力,这意味着将相关的事物尽可能紧密地联系在一起。

力求松耦合,这意味着不要让无关的东西泄漏到其他无关的范围内。

努力实现自我记录的可维护代码,数十或数百个 private static final String/int 声明混在一起不符合任何人的标准这个定义!

在 2012 年,当您现在将 Enum 作为工具时,C 风格的常量是一个糟糕的解决方案,您应该尽可能多地将这些常量组转换为 EnumEnum 是类型安全的,可以附加其他属性、属性和行为以使其成为intelligent。这就是下坡路。

【讨论】:

  • 也许添加使事物“相关”的因素很有用:它们可能一起改变,而不会对不相关的事物造成(太多)改变。
  • (仅仅因为常量在interface中,并不意味着该接口必须被实现。)
  • 凝聚力是我一直在寻找的术语 :) 从事以 constants.py 文件为标准的项目:/
【解决方案3】:

在我看来,仅仅将常量放在Constant.java 文件中是没有意义的(它只是解决了问题)。但有时我会重新组合它们以清除东西并使用几个文件来重新组合它们:DatabaseConstants.javaGraphicConstants.java 等等...... 当然,使用枚举也很有用(也是最佳实践)。

编辑:确切地说,我实际上是在使用 Java ME 应用程序,所以它只是一种“模仿”我无法拥有的枚举的方式,在抽象类中使用“受控词汇”(我想念所有的 Java EE功能...)

【讨论】:

  • 我在考虑使用这个策略,但我的问题没有反映出来,因为我还在争论是否采用那个策略。一个拥有超过 150 个模型唯一对象的应用程序(不,我们没有使用 Spring 或 struts 等)。这些模型对象中的每一个都有大量散布在各处的常量,但它是一种方法
【解决方案4】:

对于访问此页面的人。

如果你不想维护多个常量文件,下面是更好的组织方式。

public interface Constants {
    public static final String CREATE_USER = "createUser";
    // Nested Interface.
    public interface ProjectConstants {
        public static final String CREATE_PROJECT = "createProject";
        public static final String INVALID_SESSION = "Invalid Session";
        // As you know they are implicity public static final.
    }
}// Accessed as: 
Constants.ProjectConstants.CREATE_PROJECT

更新:

作为最佳实践,最好使用 Class。(参见 cmets。感谢 keplerian。)

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

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

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

public class Calculations {

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

【讨论】:

  • 是的,我们已经开始做,感谢您的回复
  • 将静态成员放入接口(并实现该接口)是不好的做法。参考stackoverflow.com/a/2659740/475511
  • 是的。我已更新以确保实施新代码的人可以遵循最佳实践..
【解决方案5】:

我想分享一个我几年前看到的常量设计模式,它可能会有所帮助。

首先创建一个 BaseConstant 文件。这将保存所有包可以使用的所有全局常量。

现在在您应用的每个子包中创建一个仅与子包相关的常量文件。所以如果你有 .一个名为 Login 的子包只将与登录相关的常量放在那里。但关键是扩展 BaseConstants。这样您就可以在 IDE 选择器中看到所有全局常量,但是当您打开文件时,您只会看到您的包常量。话虽如此,我认为常量文件会变得非常沉重和重复的值并且难以阅读。

这就是我的意思..

public class BaseConstants{

public static final String GLOBAL1= "GLOBAL string"; 

public static final String GLOBAL2= "another GLOBAL string"; 
}

现在在所有其他包中创建如下文件:

class MyPackageConstants extends BaseConstants{

public static final String LOCAL1 = "local String"
public static final String LOCAL2= "ANOTHER LOCAL string"; 
}

在您的 IDE 中键入“MyPackageConstants”。您应该看到整个应用程序的所有常量。

【讨论】:

    【解决方案6】:

    我从来没有听说过将所有的常量都放到一个 java 文件中。最好的方法是把与类相关的常量放在自己里面,但是用大写字母和下划线命名它们:EXAMPLE_CONSTANT

    【讨论】:

    • 不是我的反对意见,但问题是当多个类需要常量时,即常量与类之间的交互有关,而不是类的内部行为
    • @DNA 然后你把它们放在最合乎逻辑的类中并公开它们。
    • @owlstead 这很容易说,但可能没有“最明显的类”。当多个类依赖常量进行协作时,它们都平等地共享这些常量,并且无法决定哪个应该包含它们。当然,这并不意味着 all 常量应该放在 one 文件中。只是共享常量在共享接口中可能是最好的。以docs.oracle.com/javase/6/docs/api/javax/swing/… 为例
    • @DNA 如果常量是共享的,您可能希望创建一个单独的类这一事实是正确的。这是一个糟糕的例子,如果只是为了接口的名称(名称中与方向无关),以及它一个接口而不是带有private构造函数的final类的事实(我认为这是在“Effective Java”的某个地方)。
    • 关于这个例子的公平点,我只是没有任何可以公开发布的东西......
    【解决方案7】:

    您是否尝试过对所有常量使用枚举?我被告知这是自 Java 1.5 以来的首选方式。

    http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html

    【讨论】:

    • 枚举很棒,但它们并不总是能够替换常量——每个都应该在适用时使用。
    【解决方案8】:

    我认为,如果您有多个超过 2500 个 LOC 的 java 文件,那么决定将常量放在哪里应该是您的问题最少的问题。您应该清楚地了解重组后的系统将是什么样子。 这可能比决定在哪里粘贴常量和其他语法考虑要困难得多,但仍然需要先完成。

    【讨论】:

    • 是的,我知道,但是面对一个害怕的团队和挑剔的利益相关者(通常的情况),我想通过最短的周期和最低的风险开始我的“重构之旅”。我计划分多个阶段清理代码中的“便便”
    • 好的,换一种说法,一旦设计到位,老问题可能会消失。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-17
    相关资源
    最近更新 更多