这里如何避免循环依赖

问题描述 投票:0回答:4

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

详细描述:

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

问题是这样的:

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

简短描述:

World
模块需要了解
Player
模块(甚至间接通过
Board
/
Piece
)并且
Player
需要了解
World

非常感谢您的帮助。

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

oop design-patterns circular-dependency
4个回答
18
投票

遵循依赖倒置原则:引入一个接口,

ChessWorld
实现并且
Player
依赖于它——和/或
Player
实现并且
Piece
依赖于它(其中之一或两者都可以是)适当取决于依赖关系性质的详细信息)。这通常与依赖注入一起使用,并且,如果依赖者需要动态实例化依赖者的多个实例,则使用Factory DP。


8
投票

我认为循环依赖的味道更多地表明了架构/设计问题,不应该通过 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 依赖于玩家模块,而不是另一个方向。

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


3
投票

考虑每个对象真正需要什么,而不是当前恰好需要什么。

Piece 可能不需要了解 Player - 它需要了解的是它可以向其发送更新的内容。

因此,对于该示例,创建一个表示“PieceMessageListener”或类似内容的接口,并让 Player 实现该接口。现在,这两个具体都依赖于抽象(遵循“具体应该依赖于抽象,抽象不应该依赖于具体”的规则)。


0
投票

我要举手说……恕我直言,你可能已经过度设计了。

为什么一个作品需要了解玩家?国际象棋中的棋子要么是黑棋,要么是白棋,无论谁控制(下棋)它。

您提到“玩家模块”和“棋子模块” - 为什么它们是单独的模块?为什么它们不只是将数据类(域对象)放在同一个模块中?

如果我对此进行了过度分析或未能理解您如何构建游戏,那么请务必忽略我所说的。 OTOH也许我确实读对了?

© www.soinside.com 2019 - 2024. All rights reserved.