18

我一直认为仅仅为了保持常量而开设一个类是一个糟糕的设计。但最近,我尝试用谷歌搜索它,发现只有将接口作为常量是不好的反模式——没有提到使用常量类。

我的观点是,由于一类常量与全局变量实际上并没有太大区别,这就是为什么我反对它并倾向于重构这些类。它创建了一类完全没有上下文的数据。这些常量最好与实际使用它们的任何东西联系起来,为它们提供上下文和意义,以及将它们封装在一个类中。

其他人怎么想?

4

7 回答 7

30

全局常量很好。

全局(非常量)变量是魔鬼的工作。

于 2009-08-12T02:43:11.710 回答
17

Global constants aren't bad practice, as long as they are...

  1. ... immutable - a global, final/readonly reference to a mutable object (like a Java ArrayList<T> or a C# List<T>) is not a constant, but global state.
  2. ... needed by >1 class. If only one class needs your constants, put the constants directly in the class. (Caveat: Balance DRY vs YAGNI appropriately.)

Bloch covers the "constant interface" vs. "constant class" issue in Effective Java, and advocates the "constant class" approach. The reason why you don't want the constants in an interface is that it entices client classes to "implement" that interface (in order to access the constants without prefixing them with the interface name). You shouldn't, though - the interface isn't actually an interface to the object's capabilities, but a compile-time convenience ingrained in the class' external type. Consider this:

interface C { public static final int OMGHAX = 0x539; }
class A implements C { ... }
class B { private A a; }

Class B now unnecessarily has a dependency to C. If the implementation of A changes so that it doesn't need the constants from C, you can't remove implements C from it without breaking its external interface - someone (arguably a very stupid person, but such people abound) might reference an A object through a C reference!

By putting the constants in a class, and by making that class uninstantiable, you inform clients that the constant class really just functions as a sub-namespace. In C# you mark the class as static, in Java you'd want to make it final and give an unreachable constructor:

final class C { 
    private C() { throw new AssertionError("C is uninstantiable"); }
    public static final int OMGHAX = 0x539; 
}

If you program in Java and want the constants without prefixing them with the constant class name, you can use the import static functionality.

And yes, it's slightly redundant to be forced to create a new type just to have somewhere to put your constants, but that's a wart in languages like Java and C# that we have to deal with - we have to put our constants somewhere, and our best option happens to be a non-instantiable class.

于 2009-08-12T11:50:20.073 回答
10

全局变量是有问题的,因为它们在模块之间引入了大部分不必要的依赖关系。这些依赖关系使调试问题和重用代码变得更加困难。

我想说真正的全局常量也出于同样的原因存在问题,因此,与其让一个名为 MyGlobals 的单例包含一个像 MyGlobals.HTTP_SUCCESS_OK 这样的常量,不如将类似常量封装在它们自己的类中,例如 HttpStatus.SUCCESS_OK。

于 2009-08-12T03:19:29.357 回答
7

我相信全局变量的问题是它们创建了全局状态。全局常量不这样做,但它们确实负责一些无上下文的常量,这可能很糟糕。

如果您需要类似的东西,我建议您创建枚举(如果您有 int 常量)或常量的静态类,这样您就可以给它们一些上下文(例如,Math.PI)

于 2009-08-12T02:45:01.163 回答
4

我想没有提到的一件事是更务实的问题。如果您使用的是编译语言,请记住您必须重新编译才能更改常量的值。如果它是您可能想要经常更改的值,您可能还需要考虑一个配置文件。

于 2009-08-12T03:31:23.590 回答
3

在某些情况下,全局常量是真正恒定的最佳方法(不仅对于程序的一次构建是恒定的,而且应该在软件产品的整个生命周期及以后)。

例如,您不希望有多个类,每个类都为 pi、e 或 HTTP_SUCCESS 声明自己的常量。

另一方面,如果全局常量是可以更改的任意值,例如由于需求的变化,它们会产生许多全局变量的问题。即,如果将这些常量放入配置文件似乎是一个合理的选择,它不应该是一个全局常量。

于 2009-08-12T13:43:17.893 回答
0

全局变量已被广泛认为是一件坏事,通常应该避免使用。这就是为什么这么多人对单例模式有疑问的原因。全局变量的问题在于它们是可传递的。

于 2009-08-12T02:45:09.073 回答