1

Say I have two classes like this

public class Foo
{
    protected final Bar child;

    public Foo()
    {
        child = new Bar(this);
    }
}

public class Bar
{
    protected final Foo parent;

    public Bar(Foo parent)
    {
        this.parent = parent;
    }
}

I want to make a subclass of Foo, Foo2, which has as its child a Bar2, which is a subclass of Bar. I can do it like this:

public class Foo
{
    protected final Bar child;

    public Foo()
    {
        child = new makeChild();
    }

    protected Bar makeChild()
    {
        return new Bar(this);
    }
}

public class Foo2 extends Foo
{
    @Override
    protected Bar makeChild()
    {
        return new Bar2(this);
    }
}

However, this is supposed to be a very bad idea. But something like this won't work:

public class Foo
{
    protected final Bar child;

    public Foo()
    {
        this(new Bar(this));
    }

    protected Foo(Bar child)
    {
        this.child = child;
    }
}

because new Bar(this) refers to this before the supertype constructor has been called.

I see two means for dealing with this:

1) I could make the members private and non-final, and then make setters which throw an exception if they're already set, but that seems clumsy and only detects any coding problems at runtime.

2) I make the Foo constructor take as a parameter the Class object for the type of Bar to use, and then use reflection to invoke that class's constructor. However, that seems heavyweight for what I'm trying to do.

Is there any coding technique or design pattern I'm missing?

Community
  • 1
  • 1
Matthew Cline
  • 2,312
  • 1
  • 19
  • 36

3 Answers3

2

Is there any coding technique or design pattern I'm missing?

The dependency injection pattern comes to mind. Just take the parameters out of the constructor altogether, make the types that compose the classes above interfaces and then inject the appropriate concrete type when the need arises.

Foo interface

interface Foo {
  public void setBar(Bar bar);
  public Bar getBar();
}

Bar interface

interface Bar {
  public void setFoo(Foo foo);
  public Foo getFoo();
}

I've been looking at using Guice or something similar to decouple things even further and automatically do the injection.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
1

You question is simple question on Circular References.

First of all, you should design you classes to avoid the circular reference for many reasons stated here

Next, in case you have no option, then the best solution is using "Dependency Injection". Why? Think this way:

  1. You have to create Foo Object
  2. While creating foo, you need to create Bar also
  3. But you do not want to hard-code the Bar instanciation for obvious reasons
  4. Calling an 'overridable' method in constructor is Problematic because of reasons you mentioned

Thus Dependency Injection comes to safe rescue.

Community
  • 1
  • 1
Sandeep Jindal
  • 14,510
  • 18
  • 83
  • 121
  • "First of all, you should design you classes to avoid the circular reference for many reasons stated". Having read the linked article and then re-thought things, I've decided that the two classes really should be merged together into one class. – Matthew Cline Jun 17 '13 at 02:07
0

One of the choices is to make a separate function for initialization, and invoke the init method in child class ctor:

e.g.

class Foo {
    private Bar child;

    public Foo() {
        initWithChild(new Bar(this));
    }

    protected final void initWithChild(Bar child) {
        this.child = child;
    }
}

class Foo2 {
    public Foo2() {
        initWithChild(new Bar2(this));
    }
}

Of course, it assume Foo and Bar is coupled and it is reasonable to rely on Foo to instantiate Bar. However in most case, you should consider injecting Bar to Foo by DI frameworks.


In comment you have mentioned the need for final.

Although I don't think it is a big issue for non-final in such case as the member var is now private, here is another way (in fact similar to what described above) that you can consider IF the initialization work is as simple as in your question:

class Foo {
    protected final Bar child;

    public Foo() {
        this.child = new Bar(this);
    }
}

class Foo2 {
    public Foo2() {
        this.child = new Bar2(this);
    }
}

Haven't tested the code but I believe it should work :P

Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
  • But in that case the `child` member can't be `final`, because it isn't being set in a constructor. – Matthew Cline Jun 17 '13 at 01:37
  • Oh I haven't recognized that "final" is one of your requirement. However, given the variable is now private, having it as non-final seems to be a less critical issue. – Adrian Shum Jun 17 '13 at 01:41
  • `this(new Bar(this));` isn't going to work, since it's referring to `this` before the supertype constructor has been called. – Matthew Cline Jun 17 '13 at 01:50
  • Good catch, lemme update it a bit (Though I am curious how useful this can be :( ) – Adrian Shum Jun 17 '13 at 02:01