OO设计和循环依赖

时间:2010-10-24 07:45:59

标签: java oop circular-dependency

我正在设计我的课时遇到循环依赖问题。

自从我读到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 确实很有意义。在我描述的情况下,玩家可以离开一个团队(并且知道他是否在团队中)以及驱动移除的团队。但我同意你的观点,我不喜欢这个过程有两个“切入点”的想法。再次感谢。

4 个答案:

答案 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内。