代码之家  ›  专栏  ›  技术社区  ›  Ben J

OO设计和循环依赖

  •  19
  • Ben J  · 技术社区  · 14 年前

    在设计我的类时,我目前正努力解决循环依赖性问题。

    自从我读到 Anemic Domain Model (这是我一直在做的事情),我一直在努力摆脱创建“成堆的getter和setter”的域对象,回到我的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)?创造一个无限的循环!

    过去 我刚把这些对象做成了“哑”pojos,让服务层来完成这项工作。但即使现在,我仍然面临着这个问题:为了避免循环依赖,服务层仍然将其链接在一起——也就是说。

    public class SomeService {
    
        public void leave(Player player, Team team) {
    
            team.removePlayer(player);
            player.leaveTeam();
    
        }
    
    }
    

    我是不是太复杂了?也许我遗漏了一些明显的设计缺陷。如有任何反馈,我们将不胜感激。


    感谢大家的回答。我接受 格罗德里格斯 的解决方案,因为它是最明显的(不敢相信它没有发生在我身上)并且易于实现。然而, 倾析作用 确实很有意义。在我所描述的情况下,一个球员有可能离开一个团队(并且要知道他是否在一个团队中),也有可能离开一个团队。但我同意你的观点,我不喜欢这个过程有两个“入口点”的想法。再次感谢。

    4 回复  |  直到 8 年前
        1
  •  14
  •   Grodriguez    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..
        }
    }
    
        2
  •  8
  •   David Kerr    14 年前

    本,

    首先,我会问一个球员是否可以(逻辑上,合法地)离开球队。我想说的是,玩家对象不知道他在哪个队。他是一个团队的成员。所以,删除 Player#leaveTeam() 并通过 Team#removePlayer() 方法。

    如果您只有一个玩家,并且需要将其从团队中移除,那么您可以在团队中使用静态查找方法。 public static Team findTeam( Player player ) ...

    我知道这比 球员离开球队() 方法,但根据我的经验,您仍然可以拥有一个有意义的域模型。

    双向引用(父对象->子对象和子对象->父对象)经常充满其他内容,例如垃圾收集、维护“引用完整性”等。

    设计是妥协!

        3
  •  2
  •   Nathan Arthur user2811108    8 年前

    想法是用不同的方法做与域相关的事情,这些方法不互相调用,而是为自己的对象做与域相关的事情,即团队的方法为团队做,玩家的方法为玩家做。

    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();
        }
    
    }
    
        4
  •  1
  •   Nathan Arthur user2811108    8 年前
    public void removePlayer(Player player) {
        if (players.contains(player)) {
            players.remove(player);
            player.leaveTeam();
        }
    }
    

    同上,内部 leaveTeam .