views:

188

answers:

4

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 wich imports a ChessWidget module;

ChessWidget just wraps 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:

module Player needs to know about other players and the board (and thus importing ChessWorld!)

***Short description:

The World needs to know about player(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

+5  A: 

Follow the Dependency inversion principle: introduce an interface, which World 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.

Alex Martelli
IMHO, this doesn't solve the circular dependency. It is still there but handled by a DI container and loosely coupled through interfaces.
Cohen
Dependencies have a direction, e.g. A->B->C->A is circular, but if you invert any one of the arrows it's not a circle any more.
Alex Martelli
A: 

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?

slugster
it is because is a chess variant system, so it cul be 2 boards 7 players and werid rules
zkp0s
Ahh ok, that would explain it :)
slugster
A: 

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").

kyoryu
+1  A: 

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.

Cohen
the problem is, still, that player needs to know about board and even other players. I used a workaround separating piece and player module, by using "keys" or IDs and then doing an interface WorldInfo that World implements and Player imports. That way, importing Board, does not Imply import piece.
zkp0s