How to initialize a circular dependency (final fields referencing each other)?

与世无争的帅哥 提交于 2019-12-01 02:00:26

问题


How do you initialize this:

class A {
    final B b;

    A(B b) {
        this.b = b;
    }
}

class B {
    final A a;

    B(A a) {
        this.a = a;
    }
}

DI framework, reflection, better design?

Motivation and a use case (added):

My particular use case is simplifying field access in A's and B's sub-classes. So I'm injecting them to shortly reference them by fields in the derived classes without a need to declare explicitly in each sub-class.

There is also a recommendation on DI that objects should better be immutable: Guice best practices and anti-patterns.


回答1:


You could use a factory method

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);
            }
        };
    }
}



回答2:


Though it may look dirty, but I prefer to replace one of the final references with Supplier (like one in Guava or Java 8) like:

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));
}

where MutableSupplier looks somehow like the following:

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>();
    }

}

I know that MutableSupplier's mutability looks super-ugly for immutability enthusiasts but I found that using it is more or less acceptable in such cases :)




回答3:


What you are having is a circular dependency. The only way I can think of is to not declare the fields as final and have your dependency injected using setter injection instead of constructor injection.

A a = new A();
B b = new B();

a.setB(b);
b.setA(a);


来源:https://stackoverflow.com/questions/19808342/how-to-initialize-a-circular-dependency-final-fields-referencing-each-other

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!