Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create mutually dependent objects safely?

Tags:

java

Suppose I have the following two classes to start off with:

public class Game {
    private final Player self;
    private final Player opponent;

    public Game(final Player self, final Player opponent) {
        this.self = Objects.requireNonNull(self);
        this.opponent = Objects.requireNonNull(opponent);
    }
}

public class Player {
    private final String name;

    public Player (final String name) {
        this.name = Objects.requireNonNull(name);
    }
}

Now I have discovered that I need access to the other players (thus to the Game object) in my Player class.

One way to do it is the following, add this to the Player class:

    private Game game;

    public void setGame(final Game game) {
        this.game = Objects.requireNonNull(game);
    }

However now it breaks immutability of the game object, are there ways to preserve immutabiity of mutually created objects?

Or do I need to resort to manually imposed mutability and safety (from a regular client perspective, not from a multithreaded synchronization perspective)? Such as throwing an exception whenever someone attempts multiple setGame.

To summarize, this is the mutual dependency I am trying to solve:

Player playerSelf = new Player(/* non-existing game */, "Self");
Player playerOpponent = new Player(/* non-existing game */, "Opponent");
Game game = new Game(playerSelf, playerOpponent);

versus

Game game = new Game(/* non-existing player */, /* non-existing player */);
Player playerSelf = new Player(game, "Self");
Player playerOpponent = new Player(game, "Opponent");

Does there exist a Pattern such as for example the Builder Pattern which aids against an explosion of constructor arguments, which could be solved in a way that breaks immutability if one wanted to avoid the exposion without using the Builder Pattern?

like image 230
skiwi Avatar asked May 18 '14 20:05

skiwi


1 Answers

Whenever you have a circular dependency, break it. It will help reduce your code's coupling, increase testability, and keep you sane. Why does Player need access to the other player in the first place? You might be trying to put too much functionality into it. Perhaps you could move that into the Game? Or into, say, a Strategy that's inserted into the Player object?

Also, bear in mind that immutability isn't always the answer. Some things, like the game state, are inherently mutable. Trying to shoehorn them into immutable objects is bound to make life miserable.

like image 153
Thomas Avatar answered Sep 30 '22 06:09

Thomas