全局常量是反模式吗?
我一直认为仅仅为了保持常量而创建一个类是一个糟糕的设计。 但最近,我尝试用谷歌搜索它,发现只有一个接口作为常量是不好的反模式 - 没有提到使用一类常量。
我认为,由于常量类实际上与全局变量没有太大区别,这就是我反对它并倾向于重构此类类的原因。 它创建了一类完全没有上下文的数据。 这些常量最好与实际使用它们的任何东西联系起来,为它们提供上下文和含义,并将它们封装在一个类中。
其他人怎么看?
I've always thought having a class just for the sake of holding constants is a bad design. But recently, I've tried googling for it and found only that having an interface as a constants is bad an anti-pattern - no mention of using a class of constants.
I'm of the opinion that since a class of constants is really not much different from global variables, that's why I'm against it and tend to refactor away such classes. It creates a class of data that has absolutely no context. Those constants are much better off tied to whatever actually use them, to give them context and meaning, as well as making them encapsulated within a class.
What do other people think?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
全局常量没问题。
全局(非常量)变量是魔鬼的杰作。
Global constants are fine.
Global (non-constant) variables are the work of the devil.
全局常量并不是坏习惯,只要它们......
ArrayList
或 C#List
) 不是常量,而是全局状态。Bloch 在《Effective Java》中讨论了“常量接口”与“常量类”问题,并提倡“常量类”方法。 您不希望接口中存在常量的原因是它会诱使客户端类“实现”该接口(以便访问常量而不用接口名称作为前缀)。 不过,您不应该这样做 - 该接口实际上并不是对象功能的接口,而是类的外部类型中根深蒂固的编译时便利性。 考虑一下:
类
B
现在不必要地依赖于C
。 如果A
的实现发生更改,使其不再需要C
中的常量,则您无法在不破坏的情况下从中删除implements C
它的外部接口 - 某人(可以说是一个非常愚蠢的人,但这样的人比比皆是)可能通过C
引用来引用A
对象!通过将常量放入类中,并使该类不可实例化,您可以告知客户端常量类实际上只是充当子命名空间。 在 C# 中,您将类标记为
static
,在 Java 中,您希望将其设为final
并提供一个无法访问的构造函数:如果您在 Java 中编程并希望常量不带前缀它们带有常量类名,您可以使用
import static
功能。是的,仅仅为了有地方放置常量而被迫创建一个新类型有点多余,但这是 Java 和 C# 等语言中我们必须处理的一个问题 - 我们必须将我们的常量放在某个地方,而我们最好的选择恰好是一个不可实例化的类。
Global constants aren't bad practice, as long as they are...
final
/readonly
reference to a mutable object (like a JavaArrayList<T>
or a C#List<T>
) is not a constant, but global state.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:
Class
B
now unnecessarily has a dependency toC
. If the implementation ofA
changes so that it doesn't need the constants fromC
, you can't removeimplements C
from it without breaking its external interface - someone (arguably a very stupid person, but such people abound) might reference anA
object through aC
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 itfinal
and give an unreachable constructor: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.
全局变量是有问题的,因为它们在模块之间引入了很大程度上不必要的依赖关系。 这些依赖性使得调试问题和重用代码变得更加困难。
我想说,出于同样的原因,真正的全局常量也存在问题,因此,不要使用名为 MyGlobals 的单例,其中包含像 MyGlobals.HTTP_SUCCESS_OK 这样的常量,而是将类似的常量打包在它们自己的类中,例如HttpStatus.SUCCESS_OK。
Global variables are problematic because they introduce largely unnecessary dependencies across modules. These dependencies make it harder to debug problems and reuse code.
I'd say that truly global constants are also problematic for the same reason, So instead of having a singleton called MyGlobals containing a constant like MyGlobals.HTTP_SUCCESS_OK, package like constants together in their own classes, such as HttpStatus.SUCCESS_OK.
我认为全局变量的问题在于它们创建了全局状态。 全局常量不会这样做,但它们确实负责一些无上下文常量,这可能很糟糕。
如果你需要这样的东西,我建议你创建枚举(如果你有 int 常量)或常量的静态类,这样你就可以给它们一些上下文(例如 Math.PI)
I believe the global variables problem is that they create global state. Global constants don't do this, but they indeed is responsible for some contextless constants, which may be bad.
What I'd suggest if you need stuff like that is create enums (in case you have int constants) or static classes for constants, so you can give them some context (Math.PI, for instance)
我认为没有提及的一件事是更务实的问题。 如果您使用的是编译语言,请记住您必须重新编译才能更改常量的值。 如果您可能想要经常更改它的值,您可能还需要考虑配置文件。
I suppose one thing that's not being mentioned are the more pragmatic issues. If you're using a compiled language, bear in mind that you have to recompile to change the constant's value. If it's a value you may want to change frequently, you may also want to consider a config file.
在某些情况下,当全局常量真正保持不变时(不仅对于程序的一次构建而言是恒定的,而且应该在软件产品的整个生命周期及以后),全局常量是完美的方法。
例如,您不希望有多个类,每个类都声明自己的 pi、e 或 HTTP_SUCCESS 常量。
另一方面,如果全局常量是可以更改的任意值(例如由于需求变化),则全局常量可能会产生全局变量的许多问题。 即,如果将这些常量放入配置文件似乎是一个合理的选择,那么它不应该是全局常量。
In some cases, global constants are the perfect way to go when they are truly constant (not only constant for one build of the program, but supposedly during the whole lifespan of the software product and beyond).
For example, you wouldn't want to have several classes each declaring their own constant for pi, e or HTTP_SUCCESS.
On the other hand, global constants can create many of the problems of global variables if they are arbitrary values that could be changed e.g. because of changing requirements. I.e. if putting those constants into a config file seems like a reasonable option, it should not be a global constant.
全局变量被广泛认为是一件坏事,通常应该避免。 这就是为什么很多人对单例模式有疑问。 全局变量的问题在于它们是传递性的。
Global variables have been widely recognized as a bad thing and generally should be avoided. This is why so many people have an issue with the Singleton Pattern. The trouble with global variables is that they are transitive.