静态变量:好还是坏?

2022-09-02 09:20:18

可能的重复:
为什么静态变量被认为是邪恶的?

我有在所有程序中广泛使用静态变量的习惯,特别是当我使用Android时。我倾向于使用它们,因为有时通过 Intents 发送 10 个或更多值会很麻烦。因此,我只是将它们声明为静态变量,并使用“dot”运算符在其他类中轻松访问它们。使用静态变量的另一个原因是,当我制作一个要在整个应用程序中使用的 Utility 类时。就像我在下面给出的代码帮助我在不同的活动中使用这些变量一样

实用程序.java

public class Utility {
public static Facebook fb;
public static AsyncFacebookRunner fbAsyncRunner;
public static String[] fbPermissions = {"email", "read_stream", "user_birthday"};
public static final String PREF_UTILITY_FILE_NAME = "PrefUtilityFile";
public static SharedPreferences prefs;
public static Editor editor;
public static String access_token;
public static long expires;
}

我在网上搜索了类似的问题,并遇到了这个这个,但他们似乎没有给出这个问题的最终答案。在大多数地方,我看到相互矛盾的意见,因此完全困惑。

这是一个好的编程实践还是坏的?我应该使用它还是不使用它?


答案 1

您可以将所有静态字段替换为“Context”对象,您可以传递该对象或将其设置为单例。可以删除几乎所有的静态字段。这是否是一个好主意取决于你,但我不会假设使用实例字段必须困难得多。

顺便说一句:我会建议

  • 将静态字段/常量与使用它们的类或包放在一起
  • 如果可能的话,将静态数组视为不可变的,使它们也一样。final

您可以将非静态上下文与

public class Context {
    public static final String PREF_UTILITY_FILE_NAME = "PrefUtilityFile";

    public Facebook fb;
    public AsyncFacebookRunner fbAsyncRunner;
    public String[] fbPermissions = {"email", "read_stream", "user_birthday"};
    public SharedPreferences prefs;
    public Editor editor;
    public String access_token;
    public long expires;
}

// pass to constructor as required
class UsesContext {
    final Context context;
    public UsesContext(Context context) {
        this.context = context;
    }

    public void method() {
        // can use context
    }
}

这允许您创建具有多个上下文的单元测试。

我唯一会保持静态的是常量。


答案 2

这种编程实践在纯面向对象语言(如Java)中很糟糕,因为它破坏了面向对象的编程范式。它们可以工作,但是一旦你意识到你确实需要它们的多个版本,你就需要大量的重构来实现这一点。

如果您认为通过方法调用处理太多参数很麻烦。只需创建一个包含所有这些对象的对象(参见 Peter Lawrey 的答案“Context”对象),然后仅传递此对象。然后,您可以再次在该对象上使用“简单点表示法”。

下一点:测试。如果你需要用代理或其他测试的东西替换一些静态字段进行单元测试,你基本上就搞砸了。使用上下文对象,只需将不同的上下文对象放入单元测试即可。

你提到的类基本上是这种上下文对象的良好候选者。只需将其所有字段设置为非静态,并将该类的对象交给需要它的代码即可。Utility

我可以告诉你一个我使用静态学搞砸的例子:我曾经写过一个编译器。而且,由于我认为在编译运行期间,有许多上下文内容只需要一次(例如符号表),因此我将它们全部添加为静态变量。后来我决定允许多线程编译和“服务器”模式,其中编译器始终以空闲模式运行,直到客户端发送编译请求(这节省了Java的长启动时间)。现在我被搞砸了。现在有多个并发上下文(并发编译器线程),但所有上下文都通过静态变量共享。我需要大约一周的时间用上下文对象替换所有静态数据,并引入了许多错误。


推荐