Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么会有java单例类?你什么时候需要用_Java_Design Patterns_Singleton - Fatal编程技术网

为什么会有java单例类?你什么时候需要用

为什么会有java单例类?你什么时候需要用,java,design-patterns,singleton,Java,Design Patterns,Singleton,我知道单例类只能有一个实例化,但我不明白为什么这会有用。为什么不创建一个包含静态变量和方法的类,并在需要时使用synchronize来确保没有两个线程同时在类中执行方法呢。我只是不明白为什么有人会费劲去创建这样的类。我知道我错过了一些东西 谢谢,数据库实例是一个非常有用的地方,因为一个线程只需要一个DB连接。我打赌还有很多其他的实例,比如数据库连接,你只需要一个实例,这就是你会使用单实例的地方 只有静态方法(和私有构造函数)的类是一个根本没有实例(0个实例)的变体 singleton是一个只有一

我知道单例类只能有一个实例化,但我不明白为什么这会有用。为什么不创建一个包含静态变量和方法的类,并在需要时使用synchronize来确保没有两个线程同时在类中执行方法呢。我只是不明白为什么有人会费劲去创建这样的类。我知道我错过了一些东西


谢谢,

数据库实例是一个非常有用的地方,因为一个线程只需要一个DB连接。我打赌还有很多其他的实例,比如数据库连接,你只需要一个实例,这就是你会使用单实例的地方

只有静态方法(和私有构造函数)的类是一个根本没有实例(0个实例)的变体

singleton是一个只有一个实例的类

这些是不同的东西,有不同的用例。最重要的是国家。一个单身者通常保护对逻辑上只有一个的东西的访问。例如,应用程序中的-屏幕可能由单例表示。当创建单例时,资源和到这个单例的连接被初始化


这与使用静态方法的实用程序类有很大的区别——其中不涉及状态。如果有,则必须检查(在同步块中)状态是否已创建,然后按需初始化(延迟)。对于某些问题,这确实是一个解决方案,但您需要为每个方法调用的开销付费。

单例比具有静态变量和方法的类具有优势:它是一个对象实例,可以从类继承(例如:作为单个主体JFrame的应用程序),并扩展一个或多个接口(因此被视为实现这些接口的任何其他对象)。

何时需要使用一个接口? 有许多对象,我们只需要其中一个:线程池、缓存、对话框、处理首选项和注册表设置的对象、用于日志记录的对象,以及充当打印机和图形卡等设备驱动程序的对象。对于这些类型的对象中的许多,如果我们要输入多个,我们会运行到各种类型的对象中错误的程序行为或过度使用资源等问题

关于同步的使用这无疑是非常昂贵的,而且同步化唯一相关的时间是第一次或唯一的安装,一旦实例化,我们就不再需要再次同步。在第一次通过之后,同步化完全不需要开销:(

使用封装只应创建(初始化)的资源)每个应用程序一次。您通常对管理对共享实体(如数据库)的访问的资源执行此操作。单个线程可以控制有多少并发线程可以访问该共享资源。也就是说,因为只有一个数据库连接池,所以它可以控制有多少数据库连接分发给需要它们的线程。记录器是另一个示例,记录器确保可以适当管理对共享资源(外部文件)的访问。通常,单例还用于加载创建成本高昂(速度较慢)的资源

您通常会创建这样的单例,在getInstance上同步:

public class Singleton {

    private static Singleton instance;

    private Singleton(){
         // create resource here
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }

        return instance;
    }
}
但这样创造同样有效

public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton(){
        // create resource here
    }

    public static Singleton getInstance() {
        return instance;
    }
}

这两种方法都会为每个类加载器创建一个实例。

对于我来说,与使用静态方法的类相比,更喜欢使用单例的原因是可测试性。比如说,我实际上需要确保一个类确实有一个且只有一个实例。我可以使用单例或只使用静态方法的静态类来实现这一点。让我们来看看我想在另一个类中使用这个类,但出于测试目的,我想模拟第一个类。唯一的方法是将该类的实例注入到第二个类中,这要求您有一个非静态类。在测试方面您仍然有一些困难——您可能需要构建一些您需要的代码可以通过反射调用来删除用于测试目的的单例。您也可以使用接口(尽管这将明确允许其他开发人员使用单例以外的其他内容)只需将singleton作为接口的实例提供给使用它的类。

我不完全同意,但是关于它的一些观点是有效的,应该小心使用singleton

在我看来,用来代替单例的静态类更糟糕。静态类应该主要用于对不共享公共资源的相关函数进行分组。
java.util.Collections
就是一个很好的例子。它只是一组不与任何对象绑定的函数

另一方面,singleton是真正的对象。理想情况下,singleton的实现应该不考虑singleton模式。这将允许您在突然需要时轻松切换到使用多个实例。例如,您可能只有一个数据库连接,但您必须同时使用另一个完全无关的数据库同时。你只需将你的单例转换成“双例”或“三例”或其他任何形式。如果你需要,你也可以将其构造函数公开,这将允许创建你想要的任意多个实例。所有这些东西都不容易用静态类实现

简单地说,singleton是一个常规类,它有一个全局可用的实例,这样可以避免将它作为参数到处传递的麻烦

创建一个单例并没有太大的麻烦,只需创建一个带有私有构造函数的常规类,然后实现一个工厂方法,就完成了<
public class DBConnectionProvider implements ConnectionProvider {}
public void doSomeDatabaseAction(ConnectionProvider cp) {
   cp.createConnection().execute("DROP blah;");
}
public void doSomeDatabaseAction() {
   DBConnectionProvider.createConnection().execute("DROP blah;");
}
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
}