I typically try and avoid bidirectional relationships at all costs. Recently I’ve been trying to follow a more domain centric design philosophy and I’m looking for advice in the best way to solve a specific problem.
I am implementing a basic 2d grid. There are 3 basic classes, Item, Tile (has a list of Items), and World (has a 2d array of Tiles).
I am struggling with where to put the move() method which moves an item from one tile to a neighboring tile. My initial inclination would be to place the move method in the Item class since it is the item that is actually moving.
However, that would create a circular dependency. In the past I always worked with dumb objects in which case the move() method was in a higher layer (some kind of WorldManager or MoveManager) which knows about both tiles and items. I’m interested in what proposals others might have that can avoid the circular dependency while maintaining the domain-centric philosophy.
0
To answer your question directly:
A player would tell (by picking it up) an item to move from one tile to another. So logically, the move method goes on Item and receives the two Tiles as parameters.
Now having said that:
Don’t let DDD get in the way of single-responsibility principle. It’s ok to have non-entity items, such as MoveManager, and call it part of your domain. Just because you don’t persist it anywhere, doesn’t make it less a part of the domain.
People often confuse the data model with the behaviour (or business domain) model when talking about DDD. Anything can be an entity. In fact, one could argue that anything persisted already has its single responsibility and shouldn’t be given any more.
From MSDN:
I, for one, am not disturbed by the need to involve other, non-entity classes, and I would try to avoid lifting the central behavior outside of my entity. You should always remember that entities are intrinsically behavioral units. Often that behavior will be implemented as a kind of state machine—when you invoke a command on an entity, it is responsible for changing its internal state—but sometimes it’s necessary for you to obtain additional data or impose side-effects upon the outside world.
1
Hmm, I like the MoveManager
idea better.
Any object that moves itself would also require knowledge of the underlying surface on which it is moving, so you would have to pass the tileset to your Item
anyway. There goes your loose coupling.
Seems to me like it makes more sense to have a MoveManager object that has knowledge of the tileset and the items. This is how the real world works; the chess pieces and the chess board don’t have any built-in intelligence of their own.
For DDD, most important thing to start with is the domain knowledge. If, all you do with your ‘basic 2d grid’, is moving items from one tile to another, then why do you need to put a list of items in a tile? For what use case?
If I was you, I would be looking for aggregate root here. Probably, ‘world’ could be the one here where you could put the move method. All depends on the domain and its use cases.
A relevant exercise could be found in Effective Aggregate Design by Vaughn Vernon
I am struggling with where to put the move() method which moves an item from one tile to a neighboring tile. My initial inclination would be to place the move method in the Item class since it is the item that is actually moving.
Which class has the responsibility of maintaining the invariant?
For instance, if there’s a rule that you can only move items to neighboring tiles, then the move method should be implemented on which ever object knows which tiles are neighbors.
Caution: one of the difficulties of DDD and “simple” problems: the business rule is actually “do whatever the human operator tells you”, and there isn’t actually an invariant to be implemented in the model.