使用嵌套的公共类组织常量


21

我正在处理具有许多常量的应用程序。在最后的代码审查中,发现常量过于分散,应该将它们全部组织到一个“主”常量文件中。分歧在于如何组织它们。大多数人认为使用常量名称应该足够好,但这将导致代码如下所示:

public static final String CREDITCARD_ACTION_SUBMITDATA = "6767";
public static final String CREDITCARD_UIFIELDID_CARDHOLDER_NAME = "3959854";
public static final String CREDITCARD_UIFIELDID_EXPIRY_MONTH = "3524";
public static final String CREDITCARD_UIFIELDID_ACCOUNT_ID = "3524";
...
public static final String BANKPAYMENT_UIFIELDID_ACCOUNT_ID = "9987";

我发现这种命名约定很麻烦。我认为使用公共嵌套类可能会更容易,并且具有以下内容:

public class IntegrationSystemConstants
{
    public class CreditCard
    {
        public static final String UI_EXPIRY_MONTH = "3524";
        public static final String UI_ACCOUNT_ID = "3524";
        ...
    }
    public class BankAccount
    {
        public static final String UI_ACCOUNT_ID = "9987";
        ...
    }
}

这个想法没有得到很好的接受,因为它“太复杂了”(关于这个原因为什么太复杂,我没有得到太多细节)。我认为这会在相关常量组之间创建更好的划分,而自动完成功能也使查找这些常量变得更加容易。我从来没有见过这样做,所以我想知道这是否被接受,或者是否有更好的理由不应该这样做。


1
我比较喜欢这个主意。当我想要C#风格的枚举式作用域和行为时,我发现自己在C ++中做了类似的事情,但是具有有意义的值(我想这个主意是因为我习惯于在Scala中使用案例类代替枚举)。当然,这是一个有趣的个人项目,而不是团队合作。
KChaloux 2012年

Answers:


13

我不同意这两个建议。

常量应该在其相关的类中而不是以提议的两种形式中的任何一种在全常量类中。

不应只有常量的类/接口。

一个类CreditCard(不是内部类)应该存在。此类/接口具有与信用卡有关的方法以及常量UI_EXPIRY_MONTHUI_ACCOUNT_ID

应该存在一个类/接口BankAccount(而不是内部类)。此类/接口具有与银行帐户有关的方法以及constant UI_ACCOUNT_ID

例如,在Java API中,每个类/接口都有其常量。它们不在具有数百个常量的Constants类/接口中,无论是否分组为内部类。

例如,与结果集相关的这些常量位于接口中ResultSet

static int  CLOSE_CURSORS_AT_COMMIT 
static int  CONCUR_READ_ONLY 
static int  CONCUR_UPDATABLE 
static int  FETCH_FORWARD 
static int  FETCH_REVERSE 
static int  FETCH_UNKNOWN 
static int  HOLD_CURSORS_OVER_COMMIT 
static int  TYPE_FORWARD_ONLY 
static int  TYPE_SCROLL_INSENSITIVE 
static int  TYPE_SCROLL_SENSITIVE 

此接口具有相对于结果集的方法签名,并且实现类实现该行为。他们不仅仅是固定的持有人。

这些与UI操作相关的常量位于界面中javax.swing.Action

static String   ACCELERATOR_KEY 
static String   ACTION_COMMAND_KEY 
static String   DEFAULT 
static String   LONG_DESCRIPTION 
static String   MNEMONIC_KEY 
static String   NAME 
static String   SHORT_DESCRIPTION 
static String   SMALL_ICON 

实现类具有与UI动作相关的行为,它们不仅仅是常量持有者。

我知道至少有一个SwingConstants没有方法的“常量”接口(),但是它没有数百个常量,只有几个,它们都与UI元素的方向和位置有关:

static int  BOTTOM 
static int  CENTER 
static int  EAST 
static int  HORIZONTAL 
static int  LEADING 
static int  LEFT 
static int  NEXT 
static int  NORTH 
static int  NORTH_EAST 
static int  NORTH_WEST 
static int  PREVIOUS 
static int  RIGHT 
static int  SOUTH 
static int  SOUTH_EAST 
static int  SOUTH_WEST 
static int  TOP 
static int  TRAILING 
static int  VERTICAL 
static int  WEST 

我认为仅常量类不是好的OO设计。


1
尽管我同意仅常量类在大多数情况下是不良设计的标志,但仍有合法用途。例如,常量并不总是“属于”特定的类。一个具体的示例就是Android编程中Intent Extras的键。
curioustechizen 2014年

1
+1,但是UI常量可能不应该出现在BankAccount之类的业务模型中。它们属于某个UI类。
凯文·克莱恩

10

得出的结论是,常量过于分散,应该将它们全部组织成一个“主”常量文件。

这是常数“很难找到”的问题的100%错误解决方案。根据技术标准(例如常量,枚举或接口)对事物进行分组是一个根本性的错误(不幸的是,编程人员经常犯这种错误)。

除了层体系结构,事物应该按其域和常量进行分组,因为它们是非常底层的元素。常量应该是使用它们作为其API一部分的类或接口的一部分。如果找不到适合他们居住的自然环境,则需要清理API设计。

此外,单个巨大的常量文件会降低Java的开发速度,因为常量会在编译时内联到使用它们的类中,因此任何更改都会强制重新编译所有这些文件以及所有依赖它们的文件。如果您有一个随处使用常量的文件,那么您将在很大程度上失去增量编译的好处:观看Eclipse锁定15分钟,因为它针对该文件的每次更改都会重新编译整个项目。并且由于该文件包含在任何地方使用的所有常量,因此您将经常对其进行更改。是的,我是根据个人经验讲的。


我没有意识到对开发环境的潜在影响,我想嵌套类方法对此无济于事,对吗?
FrustratedWithFormsDesigner 2012年

1
@FrustratedWithFormsDesigner:这取决于增量编译机制在建模依赖项上花费了多少精力。
Michael Borgwardt 2012年

9

你是对的。您的建议使程序员可以import static Constants.BankAccount.*消除“ BANKACCOUNT_”的无数重复。串联不能很好地替代实际范围。也就是说,我对改变团队文化抱有很大希望。他们有适当做法的概念,即使您向他们显示100名说错了的专家,也不太可能改变。

我也想知道为什么您只有一个“常量”文件。除非这些常量都以某种方式相关并且非常稳定,否则这是非常不好的做法。更典型的是,它变成一种不断变化并受所有事物依赖的厨房水槽类。


当前,我们有一个包含大多数UI字段ID常量的常量文件,以及几个其他特定于子项目的常量文件。但是现在,与子项目相关的常量需要由其他相关子项目使用,这正是促使这些想法将它们全部合并到一个“主”常量文件中的想法。这比现在更好,因为有时我什至不知道要引用哪个常量文件来获取值,而其他人则创建了常量的副本,因为他们无法在其他子项目的常量文件中找到它。
FrustratedWithFormsDesigner 2012年

8
一个不断变化的常量类...如果您足够努力地学习,那里就会有禅宗。
KChaloux 2012年

2
@FrustratedWithFormsDesigner:用户界面字段ID?不知道在哪里找到价值?听起来像一大堆WTF。你有我的同情。
凯文·克莱恩

6

两种方法都有效,这才是最后的重要。

就是说,您的方法很常见,足以被视为一种模式,或者更准确地说,它是对恒定接口反模式的足够好的改进。我看不出有什么复杂的内容,但这是您应该与团队进行的讨论。


对于足够长的常量列表,我甚至更喜欢常量接口,而不是将它们全部放在同一个类中。从自动完成中选择错误的选项是危险的。当然,这取决于足够长的时间:)
Goran Jovic 2012年

1
@GoranJovic好吧,每个反模式都以某种方式(或至少很方便)有用,如果没有,它就不会成为模式。
扬尼斯,2012年

1

一长串常量所面临的挑战之一是找到要使用的“正确”常量。总是有人在行的末尾添加一个常量,而不是将其添加到所属的组中。

这带来了与您的团队讨论的另一点-已经通过常量的名称对它们进行了事实上的分类。因此,对于他们从当前状态到您要提出的建议来说,这确实不是什么大的转变。使用自动完成功能使不断查找变得更加容易。

如果有的话,即使可能适合特定情况,您的建议也有助于避免使用“错误”常量。通过将常量包装在一个代表性的类中,它将鼓励开发人员考虑是否应该使用它。例如,如果我CreditCard.SomeConstant选择一般用途,那么我真的应该怀疑为什么在General.SomeConstant这种情况下不存在这种情况。

我参与的项目中包含大量常量,所以我宁愿选择您建议的方法。它更干净,更直接,并且有助于避免意外使用。


1

我偶尔(在C#中)这样做,尤其是当我需要针对/解析一个众所周知且固定的XML结构或类似嵌套且字符串重的东西进行编程时,例如自定义配置块解析器。

我构建了一个嵌套的类结构,该类结构与XML的层次结构相匹配,w /类名称对应于包含const字符串“ ElementName”属性的元素和与每个Attribute(如果有)对应的相似属性的元素。

这使得针对相应的Xml编程非常容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.