为什么有java单例类?你什么时候需要使用一个

Ell*_*ott 27 java singleton design-patterns

我理解单例类只能有一个实例,但我不明白为什么这个有用.为什么不只是创建一个包含静态变量和方法的类,并在需要时使用synchronize以确保没有两个线程同时在类中执行方法.我只是不明白为什么有人会经历创造这种类的麻烦.我知道我在这里遗漏了一些东西.

谢谢,

Nam*_*ter 14

虽然我同意其他答案,但是OP问为什么没有一个带有所有静态方法的类(可能带有静态字段)而不是一个有一个实例的单例.

为什么要使用单身人士?

你可以谷歌"单身"找到各种各样的理由.来自JavaWorld:

有时只有一个类的实例是合适的:窗口管理器,打印假脱机程序和文件系统都是典型的例子.通常,这些类型的对象(称为单例)在整个软件系统中由不同的对象访问,因此需要全局访问点.当然,正当你确定你永远不会需要不止一个实例时,你可以改变主意.

为什么使用Singleton而不是使用所有静态方法的类?

有几个原因

  1. 你可以使用继承
  2. 您可以使用接口
  3. 它使得单例类本身的单元测试变得更容易
  4. 它可以对依赖单例的代码进行单元测试

对于#3,如果您的Singleton是一个数据库连接池,您希望确保您的应用程序只有一个实例,但是在没有访问数据库的情况下对数据库连接池进行单元测试(可能使用包范围构造函数或静态创作方法):

public class DatabaseConnectionPool {
  private static class SingletonHolder {
    public static DatabaseConnectionPool instance = new DatabaseConnectionPool(
        new MySqlStatementSupplier());
  }

  private final Supplier<Statement> statementSupplier;

  private DatabaseConnectionPool(Supplier<Statement> statementSupplier) {
    this.statementSupplier = statementSupplier;
  }

  /* Visibile for testing */
  static DatabaseConnectionPool createInstanceForTest(Supplier<Statement> s) {
    return new DatabaseConnectionPool(s);
  }

  public static DatabaseConnectionPool getInstance() {
    return SingletonHolder.instance;
  }

  // more code here
}
Run Code Online (Sandbox Code Playgroud)

(注意使用Initialization On Demand Holder模式)

然后,您可以DatabaseConnectionPool使用package-scope createInstanceForTest方法对其进行测试.

但请注意,使用静态getInstance()方法可能会导致"静态粘附",而依赖于单个代码的代码无法进行单元测试.因此,静态单身人士通常不被视为一种好习惯(参见此博文)

相反,您可以使用像Spring或Guice这样的依赖注入框架来确保您的类在生产中只有一个实例,同时仍然允许使用该类的代码是可测试的.由于Singleton中的方法不是静态的,您可以使用像JMock这样的模拟框架来模拟测试中的单例.