我应该在这里使用全局变量吗?

时间:2013-01-31 15:05:15

标签: java global-variables

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

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

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

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

  

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

除非它们表示已知常数,否则全局变量会引入我们称之为可变全局状态。这与单个对象具有可变数据成员时的情况形成对比 - 对象状态

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

最期望的场景(从分析代码,调试,测试等的角度来看)是,如果使用相同(或相等)的参数调用相同(或相等)的对象,此方法将执行相同的操作。对于不可变对象(具有不可变对象状态的对象),这很容易实现。

最常见的情况(实际上)是方法的行为将取决于对象的状态和参数,这意味着对于具有相同(或相等)参数的多个调用,方法可以表现不同,如果其对象的状态已经改变了(可变对象)。这不太理想,但它仍然可以轻松使用。

最不受欢迎的情况是该方法取决于全局状态。在同一(或相等)对象上使用相同(或相等)参数对同一方法进行多次调用可能会产生不同的结果。即使该对象在调用之间处于等效状态 - 或者即使它是不可变的!这显然非常难以使用,因为如果您怀疑某个方法不能执行它应该执行的操作,则无法在任何您想要的地方测试其行为。你必须至少在你正在处理的情况下测试它(可能并不总是听起来那么简单)然后对于每种情况你都可以想到它会被使用并且通常会有重要的情况你会想念的。你不能总是信任这样的方法。

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

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

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

  

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

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

答案 2 :(得分:1)

我的个人经验是这样的:如果你开始使用全局变量(或任何行为类似于全局变量的东西),你将一次又一次地使用它。最后,你会发现自己置身于意大利面条代码中。

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

我建议想一个存储这些状态的专家。这位专家将成为您的主要州级。

答案 3 :(得分:0)

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

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

这是反对天真使用全球国家的论据。这种情况有几种合法用途,但每种情况都必须根据其自身的优点进行论证。

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