2

为什么使用全局变量是个坏主意?

我想为所有要使用的类提供一组变量。它将存储关键状态,因此不能将其设置为 const (final)。

你能告诉我一些其他(正确的)方法吗?

4

4 回答 4

6

为什么使用全局变量是个坏主意?

因为它破坏了封装。所有代码都可以访问它们并修改它们。

我想让所有类都可以使用变量数组

如果所有代码只使用一个实例,则可以使用单例:

public class MyGlobalKeys {
    private static final MyGlobalKeys globals = new MyGlobalKeys();

    // disable construction outside of this class
    private MyGlobalKeys() {}

    public void getInstance() {
       return globals;
    }

    public void addKey(String key, bool state) { ... }
    public bool hasKey(String key) { ... }
    // and so on ...
}

请注意,此示例尤其不是线程安全的 - 有关改进的实现方法,请参阅Java Singleton Design Pattern

于 2013-01-31T15:07:38.497 回答
2

为什么使用全局变量是个坏主意?

除非它们用于指示已知常量,否则全局变量会引入我们所说的可变全局状态。这与单个对象具有可变数据成员(对象状态)时的情况形成鲜明对比。

考虑一个方法,它接受一些参数,做一些事情并返回一个值。

最理想的情况(从分析代码、调试、测试等的角度来看)是,如果在具有相同(或相等)参数的相同(或相等)对象上调用此方法将做同样的事情。这对于不可变对象(具有不可变对象状态的对象)很容易实现。

最常见的情况(在实践中)是方法的行为将取决于对象的状态和参数,这意味着如果方法的对象的状态发生了变化,则方法对于具有相同(或相等)参数的多个调用的行为可能不同(可变对象)。这不太理想,但它仍然可以轻松使用。

最不希望出现的情况是方法依赖于全局状态。在同一(或相等)对象上使用相同(或相等)参数多次调用同一方法可能会产生不同的结果。即使该对象在调用之间处于等效状态 - 或者即使它是不可变的!这显然很难处理,因为如果你怀疑一个方法没有做它应该做的事情,你就不能在任何你想要的地方测试它的行为。您必须至少针对您正在处理的案例进行测试(这可能并不总是像听起来那么简单),然后对于您能想到的每个案例,它都会被使用,并且通常会有重要的案例你会想念的。你不能总是相信这样的方法。

这不是解释为什么不应该使用全局变量,而是解释为什么它们通常被认为是不好的做法。

我个人使用的另一个示例是,如果您使用一段最初用于执行一次操作的代码,并让它在同一个会话中执行多次(比如将其粘贴到 GUI 上)。在这种情况下,除了第一次之外的每次运行都会发现程序处于通常不可预测的状态。这将产生令人尴尬的效果,即您的程序中的操作在第一次执行时会正确运行,并且每隔一次就有运行不正确的风险,直到程序关闭并再次运行。

我使用的另一个例子(如果前一个没有说服力)是:如果上一段的例子是这种情况,但并行?在这种情况下,执行相同操作的多个线程将在非常不可预测的点上改变彼此的状态。

你能告诉我一些其他(正确的)方法吗?

在我看来,构建程序的正确方法是将方法应该使用的状态作为一个或多个参数传递(如果它们也需要此信息,则让它将该状态传递给它调用的方法)。

于 2013-01-31T15:23:20.200 回答
1

我个人的经验是:如果你开始使用全局变量(或任何表现得像全局变量的东西),你会一次又一次地这样做。最后,您会发现自己陷入了意大利面条代码池中。

另一方面,我无法想象为什么所有(!)其他类都应该使用键状态。

我建议考虑存储这些状态的专家。这位专家将是您的关键州级。

于 2013-01-31T15:15:05.437 回答
0

非常量的全局变量是糟糕的设计,原因有很多,基本上是因为它们破坏了封装。全局变量确保你的类不能有两个不同的实例(单例遇到类似的问题)。

它们会使您的代码更难进行单元测试,并且它们会使您的代码无法并行化。考虑一个场景,您有处理输入文件的代码。每个输入文件都与其他文件分开。您想要处理整个目录,为了利用新的多核服务器,您决定使用线程一次处理 4 个文件。据推测,这应该很简单,因为处理任务完全不相关,因此不需要同步。但是,由于您使用了全局变量,因此您在代码的不同实例之间引入了全局相互依赖关系,因此线程将相互混淆彼此的内部状态并导致代码无法工作。

这是反对天真的使用全局状态的论点。有几种合法的用途,但每个案例都必须根据其自身的优点进行辩论。

至于这样做的正确方法,我将创建一个State类并将其传递给所有需要它的类的构造函数。

于 2013-01-31T15:26:52.927 回答