实用程序类应该是静态的吗?

如果我必须设计一个 Utilityclass (比如 ByteUtils 或 StreamUtils 或 StringUtils) ,那么对它们来说什么是最好的设计选择。

  • 它们是否应该是静态类(因为我不需要存储任何状态)
  • 如果它们是非静态类(这样,如果没有使用对象,它们将被 gc’d)

PS: 说到静态类,我指的是具有静态方法的类(而不是内部的静态类)

请提供有关此设计选择的建议?

58055 次浏览

如果你能使它们静止,那么一定要这样做!

换句话说,如果它们没有状态,那么它们应该是静态的。

如果是一个通用的实用程序,静态是 IMO 更好。您声明您将不会存储任何状态,所以我不明白为什么要使它非静态。将其声明为静态也会节省内存。

如果没有状态需要存储,那么 GC 就不需要存储任何东西,所以我选择 static,这样可以避免任何不必要的堆分配和 GC。

通常实用程序类包含静态方法而不包含属性,这种方法使得在不实例化类的情况下使用它们的方法变得更加容易。希望这个能帮上忙。

定义实用程序类的最简单方法是作为一个没有实例的枚举

public enum Utility {;
public static int utilityMethod(int x) { /* ... */ }
}

实用程序类不应该具有任何状态或最小状态,因此不必担心 GC。

您可以为特定目的使用其他有状态类,如 Builder、 Factory,您可以根据需要创建对象,并在完成后丢弃它。

仅仅因为某些东西可以是静态的,并不意味着它应该是静态的。

这一切还有另一个考虑因素: 嘲笑。在测试中模仿静态方法比模仿类实例的行为更难。

对我来说,谈论不必要的堆分配和对象的 GCing 有点过早优化的味道。JVM 在优化这类问题方面做得非常好。

我的实用工具类是这样的:

// final, because it's not supposed to be subclassed
public final class FooUtil {


// private constructor to avoid unnecessary instantiation of the class
private FooUtil() {
}


public static int doSomethingUseful() {
}


// ...
}

请注意,尽管这使得实用程序方法易于测试,并且从外部易于访问,但是它也使得使用它们的类难以进行单元测试,因为模仿这些实用程序方法并不容易。拥有太多这样的实用程序类可能是缺乏面向对象设计(程序编程)的标志,并且可能真的使代码难以测试。

如果你使用的是一个依赖注入框架(Spring,Guice,随便什么) ,最好使用非静态方法实例化这个工具类,并使它成为一个可注入的单例。这样,使用这些实用程序方法的类就可以通过模拟实用程序对象来进行测试。

纯实用程序类通常应该是静态的。当您有一个具有定义良好的输入和输出、没有副作用和没有状态的类时,那么根据定义,它应该是一个静态类。

一般来说,在必要之前不要增加复杂性(在这种情况下是依赖注入) ,这样做是有好处的。

使用私有构造函数使类成为非静态类是有益的:

  • 如果我们使类成为静态的,那么类将在应用程序部署时被加载,如果它是非静态的,那么类将在调用它的一个静态方法时被加载
  • 创建私有构造函数将避免实例化类

这里没有人提到静态实用程序方法是不可扩展的。你无法覆盖它们。您不能利用 OOP (特别是多物理,这是 OOP 最强大的特性)。这会导致代码复制。

附注: 我觉得这篇文章很有帮助