SIngleton对象初始化和依赖注入

时间:2015-11-03 16:16:23

标签: java singleton

我通常使用单例持有者模式创建单例类,如下所示:

public class Foo {

    private static final class SingletonHolder {
        private static final Foo INSTANCE = new Foo();
    }  

    private Foo(){}

    public static final Foo getInstance(){
        return SingletonHolder.INSTANCE;
    }

}

一切都好。但是,如果我需要注入一个依赖项来初始化单例对象呢?

在这种情况下,我添加了一个接收依赖项的方法initialize,并且必须只调用一次:

public class Foo {

    private static final class SingletonHolder {
        private static final Foo INSTANCE = new Foo();
    }  

    private Foo(){}

    public static final void initialize(Dependency d) {
        SingletonHolder.INSTANCE.setDependency(d);
    }

    public static final Foo getInstance(){
        return SingletonHolder.INSTANCE;
    }

}

我是以正确的方式吗?还有其他解决方案吗?我知道这取决于程序,我的逻辑等等......但是一般应该如何解决这个问题呢?

2 个答案:

答案 0 :(得分:1)

这种方法的问题是可以多次调用initialize方法,并且代码中没有迹象表明正在使用线程安全来处理依赖项。

如果你对此很好,那么你的懒惰初始化习惯用法就好了。

否则,在单例实例中多次设置依赖项时,可以抛出IllegalStateException或以其他方式静默执行任何操作。

修改

正如Andy Thomas所说,你也没有检查是否在调用getInstance之前设置了依赖关系,或者至少你的代码没有显示它。

答案 1 :(得分:1)

我认为你过于复杂了。在我工作的一些地方(包括我现在的地方),我们不会试图强制执行单身人士。实际应用程序的所有连接都在一个地方完成,因此如果您搜索构造函数的用法,您应该在src中找到一个,在test中可能找到多个。请参阅下面的代码。

您的方法的一些缺点:

  • 你失去了不变性,Foo的依赖可以改变
  • setDependencyinitialize方法都是生产中的测试代码
  • 您的构造函数不会创建有效对象,构造函数的后半部分位于initialize方法中,您必须记住在调用构造函数后调用
  • SingletonHolder是锅炉铭牌代码,我不知道您为什么不直接声明public static final Foo instance字段?
  • 仍然可以使用反射API和对象序列化机制创建Foo的多个实例
public class Foo {

    private final Dependency dependency;

    public Foo(Dependency dependency) {
        this.dependency = dependency;
    }

    // ...
}

public class Dependency {
    // ...
}