如何在这里避免循环依赖

时间:2009-12-26 00:00:55

标签: design-patterns

有没有办法避免循环依赖,除了混合模块,在这样的安排(它是国际象棋应用程序)

详细说明:

  • Gui模块导入ChessWidget模块;
  • ChessWidget只需封装ChessWorld模块并导入CellButton;
  • CellButton模块导入模块Cell;
  • ChessWorld模块导入Board(代表它)和Players(通知他们并获取他们的动作);
  • Board模块导入模块Piece;
  • Piece模块导入模块Player;

这里是问题所在:

Player模块需要了解其他玩家和棋盘,从而导入ChessWorld

简短说明:

World模块需要知道Player模块(甚至间接地通过Board / Piece)和Player需要了解{{1} }}

非常感谢帮助。

PS:不是因为我不能使用循环依赖,而是因为它们是邪恶的。

4 个答案:

答案 0 :(得分:15)

关注Dependency inversion principle:介绍一个ChessWorld实现的接口,以及Player所依赖的接口 - 和/或Player实现的接口Piece {{1}} 1}}取决于(取决于依赖性的细节,其中一个或两个可能是合适的)。这通常与Dependency Injection一起使用,并且,如果依赖项需要使用Factory DP动态实例化依赖项的多个实例。

答案 1 :(得分:6)

我认为循环依赖的气味显示出更多的建筑/设计问题,不应该通过DI,后期边界,松散耦合或任何其他形式的额外抽象层来解决。虽然它们都是非常好的机制,但是没有解决下面的问题。

简短:我认为 ChessWorld 持有太多责任。如果你拆分它们,你可能会发现依赖关系更适合在一个单独的模块中使用。

很长的解释:我会尝试举例说明我将如何重构它,虽然这很难,因为我现在不是完整的问题域。

注意:我不熟悉Java,所以我可能会误解导入和换行的含义。

但据我所知,依赖关系看起来有点像这样:

Gui <- ChessWidget <- ChessWorld <- CellButton <- Cell
                                 <- Board <- Piece <- Player
                                 <- Players <- ChessWorld

恕我直言,问题在于ChessWorld承担着太多不同的责任。在像PlayerList,RegisteredUsers或OnlineUsers等类似的单独模块中维护玩家列表可能更好。在重构之后,您的依赖关系会发生如下变化:

 Gui <- ChessWidget <- ChessWorld <- CellButton <- Cell
                                  <- Board <- Piece <- Player
                                  <- Playerlist <- Player

PlayerList可能是玩家模块中的内容。现在Chessworld依赖于玩家模块,而不是另一个方向。

我不确定它是否完全符合您的意图,但我对此非常感兴趣,所以请发表评论。

答案 2 :(得分:3)

考虑每个对象真正需要的东西,而不是目前恰好需要的东西。

A Piece可能不需要了解播放器 - 它需要知道的是它可以发送更新的内容。

因此,对于该示例,创建一个表示“PieceMessageListener”或其他类似的接口,并让Player实现该接口。现在,两种结构都取决于抽象(遵循“结核应该取决于抽象,抽象不应该依赖于结核”的规则)。

答案 3 :(得分:0)

我要把手伸到这里说...恕我直言你可能过度设计了这个。

为什么一件作品需要掌握玩家的知识?国际象棋中的一块是黑色或白色,无论是谁控制(播放)它。

你提到“播放器模块”和“片模块” - 为什么它们是独立的模块?为什么它们只是在同一模块中的数据类(域对象)?

如果我对此进行过分析或未能理解你如何构建游戏,那么无论如何都要忽略我说的话。 OTOH也许我确实读过正确的东西?