This is a question about how to better handle circular dependency. Let me preface by saying I think circular dependency is rarely necessary, but the code is handed down to me and I can't help it.
Suppose there is a circular dependency on classes with a conceptually equal standing, ie there is no apparent "owns" relation between them. How do I handle them gracefully?
Lets take an example where we want to represent a mutable topology of rooms, with neighbour a reflexive property
interface Room {
public void remove(Room r);
}
class Living implements Room {
Room[] neighbour;
public void remove(Room r) {/* implementation */}
}
class Dining implements Room {
Room[] neighbour;
public void remove(Room r) {/* implementation */}
}
Now, clearly we cannot call remove on the other Room in the implementation of remove, this is obviously endless recursion. But then I am left with a few options:
- Make one
Roomown another, somehow document the fact, and then only one type ofRoomhas theremovecapability. - Make a second method
removeSelf, where it never calls the methods of the otherRoom, thereby resolving the infinite recursion. - Have a
Buildingobject higher on the hierarchy and have it do all the operations onRoom
And their respective disadvantages are
- Very counter-intuitive and imposes an artificial structure when there is none. Also, at least one owning
Roommust exist within some neighbour. - Adds a method that should never be called by users, this sucks as an interface.
- Requires an owning object, sometimes also a very awkward structure, a
Buildingis only coincidentally fitting to be an owning object.
So, the question, what is a better design if circular dependency is somehow unavoidable?
We could probably make a RoomOperator class containing functions to operate on Rooms, but it also suffers the same problems as the removeSelf method above: it eventually calls a method that is illegal outside of RoomOperator.