How do i finalize "parent-child" relationships between non-inherited classes?

Viewed 59

Golf course example: We have the classes Course, Track, Tee, and Hole.

public class Course {
    private final List<Track> tracks;
}
public class Track {
    private final Course parent;
    private final Tee tee;
    private final Hole hole;
}
public class Tee {
    private final Track parent;
}
public class Hole {
    private final Track parent;
}

There is a lot of parenting going on here.

  • Course must consist of 18 tracks, as is normal in golf.
  • Track must come with each a Tee and Hole, but must also specify a parent Course which it belongs to
  • Tee and Hole must also specify a parent, but an instance of Track, to which they each belong to.

But I am running into a problem. When i try to call the constructor of Track...

public Track(Course parent, Tee tee, Hole hole) {//}

... i must pass both an instance of Tee and Hole, but...

public Hole(Track parent) {//}

... the constructors of these demand that I pass an instance of Track. And i'm stuck with a recursive problem.

I could "workaround" this by not making each parent member of these classes final anymore, but that just feels hacky, like bad practice - and there is no reason for them to not be final as they will never change in my use case.

Something else i can think of, is outsourcing "parent-child" relationships like these to a different manager-type class; not too excited about doing something like that either though.

Question

What is the proper way to handle such "parent-child" relationships, with the goal in mind to have them finalized and having simple and quick access to methods like #getParent()?

Thank you

1 Answers

I don't think this is possible to achieve with final fields. You have something similar to circular dependency - you need the parent to initialize the child, and at the same time you need the children when initializing that same parent. The best i can come up with is making the parent non-final and using the setter method to enforce setting the field only once.

public class Track {

    private Course parent;
    private final Tee tee;
    private final Hole hole;

    public Track(Tee tee, Hole hole) {
        this.tee = tee;
        this.hole = hole;
    }

    public void setParent(Course parent) {
        if (this.parent != null) {
            //already has been set, so not allowing it
            //or throw exception, whatever you need
            return;
        }
        this.parent = parent;
    }
}

This should make the parent field effectively final.

Related