除了混合模块之外,有没有办法在这样的安排中避免循环依赖(这是一个国际象棋应用程序)
详细描述:
Gui
模块导入 ChessWidget
模块;ChessWidget
只是包装 ChessWorld
模块并导入 CellButton
;CellButton
模块导入模块Cell
;ChessWorld
模块导入Board
(代表它)和Players
(通知它们并获取它们的移动);Board
模块导入模块Piece
;Piece
模块导入模块Player
;问题是这样的:
Player
模块需要了解其他玩家和棋盘,因此导入ChessWorld
!
简短描述:
World
模块需要了解Player
模块(甚至间接通过Board
/Piece
)并且Player
需要了解World
。
非常感谢您的帮助。
PS:不是因为我不能使用循环依赖,而是因为它们是邪恶的。
我认为循环依赖的味道更多地表明了架构/设计问题,不应该通过 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 依赖于玩家模块,而不是另一个方向。
我不确定这是否完全符合您的意图,但我对此非常有兴趣讨论,所以请评论。
考虑每个对象真正需要什么,而不是当前恰好需要什么。
Piece 可能不需要了解 Player - 它需要了解的是它可以向其发送更新的内容。
因此,对于该示例,创建一个表示“PieceMessageListener”或类似内容的接口,并让 Player 实现该接口。现在,这两个具体都依赖于抽象(遵循“具体应该依赖于抽象,抽象不应该依赖于具体”的规则)。
我要举手说……恕我直言,你可能已经过度设计了。
为什么一个作品需要了解玩家?国际象棋中的棋子要么是黑棋,要么是白棋,无论谁控制(下棋)它。
您提到“玩家模块”和“棋子模块” - 为什么它们是单独的模块?为什么它们不只是将数据类(域对象)放在同一个模块中?
如果我对此进行了过度分析或未能理解您如何构建游戏,那么请务必忽略我所说的。 OTOH也许我确实读对了?