这里如何避免循环依赖

发布于 2024-08-16 06:04:22 字数 847 浏览 5 评论 0原文

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

详细描述:

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

问题是:

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

简短描述:

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

非常感谢帮助。

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

Is there a way to avoid circular dependencies, other than mixing modules, in a arrangement like this(it is a chess application)

Long description:

  • There is the Gui module which imports a ChessWidget module;
  • ChessWidget just wraps the ChessWorld module and imports CellButton;
  • The CellButton module imports the module Cell;
  • The ChessWorld module imports Board (to represent it) and Players (to notify them and fetch their moves);
  • The Board module imports module Piece;
  • The Piece module imports module Player;

AND HERE IS THE PROBLEM:

The Player module needs to know about other players and the board, thus importing ChessWorld!

Short description:

The World module needs to know about the Player module (even indirectly by Board/Piece) and Player need to know about World.

Help is very appreciated.

PS: Is not because I cant use circular dependencies, but because they are evil.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

神回复 2024-08-23 06:04:22

遵循依赖倒置原则:引入一个ChessWorld实现的接口,以及 Player 依赖哪个 - 和/或 Player 实现的一个以及 Piece 依赖哪个(其中之一或两者都可能合适,具体取决于细节)依赖的性质)。这通常与依赖注入一起使用,并且,如果依赖项需要动态实例化多个实例依赖者,与工厂 DP。

Follow the Dependency inversion principle: introduce an interface, which ChessWorld implements, and on which Player depends -- and/or one which Player implements and on which Piece depends (either or both may be appropriate depending on details on the nature of the dependency). This often goes together with Dependency Injection, and, if the dependant needs to dynamically instantiate a number of instance of the dependees, with Factory DPs.

泼猴你往哪里跑 2024-08-23 06:04:22

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

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

I think the smell of a circular dependency shows more an architectural/design issue, that shouldn't be solved by DI, late bounding, loose coupling, or any other form of an extra abstraction layer. Although they are all very good mechanisms, but don't solve the problem underneath.

Short: I think the ChessWorld holds too many responsibilities. If you split them up you'll probably will find that the dependencies are responsibilities better suited in a separate module.

Long explanation: I'll try to give an example of how I would refactor it, although it's hard because I don't really now the full problem domain.

NOTE: I am not familiar with Java so I may misunderstand the implications of import and wrap.

But as I understand the dependencies look somewhat like this:

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

IMHO the problem is that ChessWorld holds too many different responsibilities. Maintaining the list of players is probably better in a separate module like PlayerList, RegisteredUsers or OnlineUsers or something similar. After that refactoring your depedencies would change as follows:

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

PlayerList is probably something you would have in the player module. Now Chessworld depends on the player module and not in the other direction.

I am not sure if it fits your intention perfectly, but I am very interested in discussing this, so please comment.

放低过去 2024-08-23 06:04:22

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

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

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

Consider what each object really needs, and not what it just happens to need at the moment.

A Piece probably doesn't need to know about a Player - what it needs to know about is something that it can send updates to.

So, for that example, create an interface representing a "PieceMessageListener" or some such, and have the Player implement that. Now, both concretions are depending upon an abstraction (going to the rule of "concretions should depend upon abstractions, abstractions should not depend upon concretions").

じее 2024-08-23 06:04:22

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

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

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

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

I'm gonna stick my hand up here and say... IMHO you may have over-designed this.

Why does a piece need to have knowledge of the player? A piece in chess is either black or white, irrespective of who is controlling (playing) it.

You mention "player module" and "piece module" - why are they separate modules? Why aren't they just data classes (domain objects) together in the same module?

If i have over analyzed this or failed to understand how you have constructed your game then by all means ignore what i said. OTOH maybe i did read things right?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文