使用getInstance vs公共声明的单例

时间:2019-11-17 11:31:01

标签: java oop design-patterns singleton

仅将变量设为公共变量并访问实例时,创建getInstance()有什么意义?

我知道抽象工厂设计模式对工厂有意义,因为我们在运行时决定所需的实现类型。

使用getInstance():

public class ClientFactory {
    private static ClientFactory instance = null;

    private ClientFactory() { }

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

公开变量而不是创建实例方法:

 public class ClientFactory {
    public static final ClientFactory instance = new ClientFactory ();
    private ClientFactory() { }
 }

,我们可以使用ClientFactory.instance.foo();轻松获得访问权限。

3 个答案:

答案 0 :(得分:1)

后面的示例很热切-总是创建ClientFactory。当可能性很小时,可能会使用ClientFactory并且实例化它会很昂贵。

第一个是懒惰的。这意味着,当不使用ClientFactory时,根本不会创建它。除了ClientFactory是不可变的,而公共字段可以被覆盖。它的实例化也是安全的,因为它受到synchronized的保护。

出于安全考虑,当客户调用以下行时(在第一种情况下):

ClientFactory.instance = null;

答案 1 :(得分:1)

使用getInstance()之类的FactoryMethod可以为将来的更改提供更多选择。

例如

  • 延迟加载
  • 用其代理之一替换实际的类
  • 用其一个子级替换类(如果有一天ClientFactory演变为具有不同子级实现的抽象类),等等。

答案 2 :(得分:1)

正如其他人正确指出的那样,这两种方法之间的主要区别在于,第一种方法将使用惰性实例化,而第二种方法将急于创建对象。应该将第二个方法中的ClientFactory字段标记为final,以避免让此类客户重新分配该字段。

第一种方法也使用synchronized,这可能会对性能产生影响,因为在第一次成功分配字段后-以后就不需要同步了。因此,对于这种方法,您也可以将initialization-on-demand与holder实例一起使用(因为您为单例使用静态字段):

public class ClientFactory {

    private ClientFactory() { }

    private static class ClientFactoryHolder {
        private static final ClientFactory INSTANCE = new ClientFactory();
    }

    public static ClientFactory getInstance() {
        return ClientFactoryHolder.INSTANCE;
    }
}

它利用JVM类的初始化。如果有人调用ClientFactoryHolder.INSTANCE方法,则ClientFactory.getInstance字段将仅被初始化,因为类将在首次引用时进行初始化。还请注意,由于JVM会为我们负责,现在getInstance方法不必同步。