如何初始化:
class A {
final B b;
A(B b) {
this.b = b;
}
}
class B {
final A a;
B(A a) {
this.a = a;
}
}
DI框架,反思,更好的设计?
动机和用例(已添加):
我的特定用例是简化A
和B
子类中的字段访问。所以我注入它们很快就会通过派生类中的字段引用它们,而不需要在每个子类中显式声明。
还有一项关于DI的建议,即对象最好是不可变的:Guice best practices and anti-patterns。
答案 0 :(得分:6)
您可以使用工厂方法
class A {
final B b;
A(B b) {
this.b = b;
}
}
abstract class B {
final A a;
B() {
this.a = constructA();
}
protected abstract A constructA();
}
public class C {
public static void main(String []args){
new B(){
protected A constructA(){
return new A(this);
}
};
}
}
答案 1 :(得分:1)
虽然它可能看起来很脏,但我更愿意用final
替换其中一个Supplier
引用(例如Guava
或Java 8
中的一个),如:
class A {
final Supplier<B> b;
A(Supplier<B> b) {
this.b = b;
}
// keeping this constructor just for usability's sake
A(B b) {
this.b = ofInstance(b); // using Guava's Suppliers.ofInstance here
}
}
class B {
final A a;
B(A a) {
this.a = a;
}
}
public static void main(String[] args) {
// using MutableSupplier.create() static factory method
MutableSupplier<B> bRef = create();
A a = new A(bRef);
B b = bRef.set(new B(a));
}
其中MutableSupplier
看起来如下所示:
import com.google.common.base.Supplier;
public class MutableSupplier<T> implements Supplier<T> {
private boolean valueWasSet;
private T value;
private MutableSupplier() {
}
@Override
public T get() {
if (!valueWasSet) {
throw new NullPointerException("Value has not been set yet");
}
return value;
}
public T set(final T value) {
if (valueWasSet) {
throw new IllegalStateException("Value has already been set and should not be reset");
}
this.value = value;
this.valueWasSet = true;
return value;
}
public static <T> MutableSupplier<T> create() {
return new MutableSupplier<T>();
}
}
我知道MutableSupplier
的可变性对于不变性爱好者来说看起来非常丑陋,但我发现在这种情况下使用它或多或少是可以接受的:)
答案 2 :(得分:0)
您所拥有的是循环依赖。我能想到的唯一方法是不将字段声明为final,并使用setter注入而不是构造函数注入来注入依赖项。
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);