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

前端 未结 3 484
轮回少年
轮回少年 2021-01-12 09:05

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;
           


        
相关标签:
3条回答
  • 2021-01-12 09:30

    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 :)

    0 讨论(0)
  • 2021-01-12 09:39

    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);
                }
            };
        }
    }
    
    0 讨论(0)
  • 2021-01-12 09:44

    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);
    
    0 讨论(0)
提交回复
热议问题