I am currently struggling with a circular dependency problem when designing my classes.
Ever since I read about the Anemic Domain Model (something I was doing all the time), I have really been trying to get away from creating domain objects that were just "buckets of getters and setters" and return to my OO roots.
However, the problem below is one that I come across a lot and I'm not sure how I should solve it.
Say we have a Team class, that has many Players. It doesn't matter what sport this is :) A team can add and remove players, in much the same way a player can leave a team and join another.
So we have the team, which has a list of players:
public class Team {
private List<Player> players;
// snip.
public void removePlayer(Player player) {
players.remove(player);
// Do other admin work when a player leaves
}
}
Then we have the Player, which has a reference to the Team:
public class Player {
private Team team;
public void leaveTeam() {
team = null;
// Do some more player stuff...
}
}
One can assume that both methods (remove and leave) have domain-specific logic that needs to be run whenever a team removes a player and a player leaves a team. Therefore, my first thought is that when a Team kicks a player, removePlayer(...) should also call the player.leaveTeam() method...
But then what if the Player is driving the departure - should the leaveTeam() method call team.removePlayer(this)? Not without creating an infinite loop!
In the past, I'd have just made these objects "dumb" POJOs and had a service layer do the work. But even now I'm still left with that problem: to avoid circular dependencies, the service layer still has link it all together - i.e.
public class SomeService {
public void leave(Player player, Team team) {
team.removePlayer(player);
player.leaveTeam();
}
}
Am I over complicating this? Perhaps I'm missing some obvious design flaw. Any feedback would be greatly appreciated.
Thanks all for the responses. I'm accepting Grodriguez's solution as it is the most obvious (can't believe it didn't occur to me) and easy to implement. However, DecaniBass does make a good point. In the situation I was describing, it is possible for a player to leave a team (and be aware of whether he is in a team or not) as well as the team driving the removal. But I agree with your point and I don't like the idea that there's two "entry points" into this process. Thanks again.