我可以用几种不同的方式初始化复杂的对象(具有注入(inject)的依赖关系和所需的注入(inject)成员设置),这些方法似乎都是合理的,但是有各种优点和缺点。我将举一个具体的例子:
final class MyClass {
private final Dependency dependency;
@Inject public MyClass(Dependency dependency) {
this.dependency = dependency;
dependency.addHandler(new Handler() {
@Override void handle(int foo) { MyClass.this.doSomething(foo); }
});
doSomething(0);
}
private void doSomething(int foo) { dependency.doSomethingElse(foo+1); }
}
如您所见,构造函数执行3件事,包括调用实例方法。有人告诉我,从构造函数调用实例方法是不安全的,因为它绕过了编译器对未初始化成员的检查。 IE。在设置
doSomething(0)
之前,我可以调用this.dependency
,它可以编译但不起作用。重构它的最佳方法是什么?doSomething
静态并显式传递依赖项?在我的实际情况中,我有三个实例方法和三个彼此依赖的成员字段,因此,要使这三个函数全部变为静态,这似乎有很多额外的样板。 addHandler
和doSomething
移到@Inject public void init()
方法中。虽然与Guice一起使用将是透明的,但它需要进行任何手动构造才能确保调用init()
,否则如果有人忘记了,该对象将无法发挥全部功能。此外,这还暴露了更多的API,这两个API似乎都是不好的主意。 私有(private)最终Dependency依赖关系;
公共(public)DependecyManager(依赖关系){...}
公共(public)doSomething(int foo){...}
}
@Inject public MyClass(DependencyDependency){
DependencyManager管理器=新的DependencyManager(dependency);
manager.doSomething(0);
}
这将实例方法从所有构造函数中拉出,但是生成了额外的类层,当我已经拥有内部和匿名类(例如该处理程序)时,它可能会变得困惑-当我尝试这样做时,我被告知将
DependencyManager
移到一个单独的位置文件,这也是令人讨厌的,因为它现在是由多个文件完成的一件事情。 那么处理这种情况的首选方法是什么?
最佳答案
尽管在这种情况下我找不到任何论据,但《有效Java》中的Josh Bloch建议使用静态工厂方法。但是,Java Concurrency in Practice中也有类似的情况,专门用于防止从构造函数中泄漏对this
的引用。应用于这种情况,它看起来像:
final class MyClass {
private final Dependency dependency;
private MyClass(Dependency dependency) {
this.dependency = dependency;
}
public static createInstance(Dependency dependency) {
MyClass instance = new MyClass(dependency);
dependency.addHandler(new Handler() {
@Override void handle(int foo) { instance.doSomething(foo); }
});
instance.doSomething(0);
return instance;
}
...
}
但是,这可能不适用于您使用的DI注释。