我正在设计我的课时遇到循环依赖问题。
自从我读到Anemic Domain Model(我一直在做的事情)以来,我一直在努力摆脱创建仅仅是“吸气剂和固定器桶”的域对象并返回我的OO根源。
然而,下面的问题是我经常遇到的问题,我不确定应该如何解决。
假设我们有一个团队类,有很多玩家。这是什么运动并不重要:)球队可以添加和删除球员,就像球员离开球队并加入另一球员一样。
所以我们有一个团队,其中有一个球员名单:
public class Team {
private List<Player> players;
// snip.
public void removePlayer(Player player) {
players.remove(player);
// Do other admin work when a player leaves
}
}
然后我们有玩家,其中有一个团队参考:
public class Player {
private Team team;
public void leaveTeam() {
team = null;
// Do some more player stuff...
}
}
可以假设两种方法(删除和离开)都具有特定于域的逻辑,只要团队移除玩家并且玩家离开团队就需要运行这些逻辑。因此,我首先想到的是,当一个团队踢一个玩家时,removePlayer(...)也应该调用player.leaveTeam()方法......
但是,如果播放器正在推动离开 - 如果leaveTeam()方法调用team.removePlayer(this)该怎么办?不是没有创造无限循环!
在过去中,我刚刚将这些对象设为“哑”POJO,并让服务层完成工作。但即使是现在我仍然存在这个问题:为了避免循环依赖,服务层仍然将它们连接在一起 - 即
public class SomeService {
public void leave(Player player, Team team) {
team.removePlayer(player);
player.leaveTeam();
}
}
我是否过于复杂?也许我错过了一些明显的设计缺陷。任何反馈将不胜感激。
感谢大家的回复。我接受 Grodriguez 的解决方案,因为它是最明显的(不能相信它没有发生在我身上)并且易于实现。但是, DecaniBass 确实很有意义。在我描述的情况下,玩家可以离开一个团队(并且知道他是否在团队中)以及驱动移除的团队。但我同意你的观点,我不喜欢这个过程有两个“切入点”的想法。再次感谢。
答案 0 :(得分:14)
你可以通过添加防守来打破循环依赖关系来检查球队是否还有球员/球员仍然在球队中。例如:
在课程Team
中:
public void removePlayer(Player player) {
if (players.contains(player))
{
players.remove(player);
player.leaveTeam();
// Do other admin work when a player leaves
}
}
在课程Player
中:
public void leaveTeam() {
if (team != null)
{
team.removePlayer(this);
team = null;
// Do some more player stuff..
}
}
答案 1 :(得分:8)
本,
我首先会问一个玩家是否可以(合乎逻辑地,合法地)从团队中移除自己。我会说玩家对象不知道他在哪个团队(!),他是团队的一员。因此,请删除Player#leaveTeam()
并通过Team#removePlayer()
方法进行所有团队更改。
如果您只有一名玩家并且需要将其从团队中删除,那么您可以在团队public static Team findTeam( Player player ) ...
上使用静态查找方法
我知道这比Player#leaveTeam()
方法更不令人满意和自然,但根据我的经验,你仍然可以拥有一个有意义的领域模型。
双向引用(父级 - &gt; Child和Child-&gt; Parent)通常充满了其他东西,比如垃圾收集,维护“参照完整性”等等。
设计是妥协!
答案 2 :(得分:2)
想法是用不同的方法做与域相关的东西,这些方法不会相互调用,而是为自己的对象做域相关的东西,即团队的方法为团队做,而玩家的方法为玩家做它
public class Team {
private List<Player> players;
public void removePlayer(Player player) {
removePlayerFromTeam(player);
player.removeFromTeam();
}
public void removePlayerFromTeam(Player player) {
players.remove(player);
//domain stuff
}
}
public class Player {
private Team team;
public void removeFromTeam() {
team = null;
//domain stuff
}
public void leaveTeam() {
team.removePlayerFromTeam(this);
removeFromTeam();
}
}
答案 3 :(得分:1)
public void removePlayer(Player player) {
if (players.contains(player)) {
players.remove(player);
player.leaveTeam();
}
}
同样在leaveTeam
内。