user3433393
user3433393

Reputation: 61

Java: how to create instances of two different classes in a third class and pass references to each other through the constructors

This is more of a theoretical question. Suppose I have 3 classes A, B and C. What I want to do is this:

public class A {
  B b = new B(c);
  C c = new C(b);
}

public class B {
  public B(C c) {

  }
}

public class C {
  public C(B b) {

  }
}

I know this code wont work. So, is there another way to do it?

Upvotes: 0

Views: 139

Answers (5)

Robby Cornelissen
Robby Cornelissen

Reputation: 97227

Not through the constructors I'm afraid. The conventional way to go about it, would be to create the appropriate setters in B and C and then use those:

public class A {
    B b = new B();
    C c = new C();

    {
        b.setC(c);
        c.setB(b);
    }
}

Introducing this kind of circular reference is a serious design smell though.

Upvotes: 0

tucuxi
tucuxi

Reputation: 17945

There are many ways to deal with it, none of them ideal:

The deferred-construction approach:

B b = new B();   
C c = new C();
b.setC(c);
c.setB(b);       // until this point, initialization is not complete

The break-the-cycle approach:

B b = new B();   // B is not fully initialized until later
C c = new C(b);
b.setC(c);       // everything set

The one-sets-the-other approach:

B b = new B();   // internally initializes its 'C' instance
C c = b.getC();  // uses the C instance set by B

// inside B
public B() {
   c = new C(this);  // leaking 'this' in constructor, not ideal
}

And then there is the Recommended Way (TM):

D d = new D(); // isolates what B needs from C and C needs from B
B b = new B(d);
C c = new C(d);

which is based on the observation that there is typically no need for B and C to depend fully on each other - you can take the common part and isolate it D, and share that.

Upvotes: 1

Tim B
Tim B

Reputation: 41208

You are correct, you can't do this. Something else that is unsafe as well so DO NOT DO THIS is:

public class A {
  B b = new B(this);
  C c = new C(this);
}

public class B {
  public B(A a) {

  }
}

public class C {
  public C(A a) {

  }
}

This sort of circular dependency can only be resolved by using a setter method to initialize either B or C after the other one has been created.

However the very fact you need to do this suggests to me that there is an architectural problem here, these classes are far too tightly coupled and you really need to think about design.

Upvotes: 0

Chris K
Chris K

Reputation: 11927

Circular dependencies are always worth avoiding. There is no direct way to achieve what you have tried to do via constructors, which is a good thing as this is a code smell and it suggests that some thought time in designing out the circular reference would be worth while.

However if you are determined then the solution is to set the back link after construction. Either via a lazy fetcher, or using a setter like this:

public class A {  
    B b = new B();
    C c = new C(b);

    { 
      b.setC(c);
    }
}

class B {
    public B() {

    }

    public void setC( C c ) {}
}

class C {
    public C(B b) {

    }
}

Upvotes: 0

Henry
Henry

Reputation: 43758

There is no way if you insist to pass the other class instance via the constructor. It is classical chicken and egg problem.

To break this you need to add a method in one of the classes to set the reference at a later time, after construction.

Upvotes: 0

Related Questions