Trade Offs!

Today I was on a mission to reduce coupling in my Java TTT. I felt as thought the User Interface was doing more than it should have to, and possibly had some feature envy from the Board class since it was validating input against the available cells.

I wanted to move the board validation into the Game class, so that the reasons for the change in the UserInterface were reduced.

By moving the validation out of the UserInterface, it then meant that the Players could not mark the board directly, so that responsibility also moved to the Game class. The flow for board marking was then:

  • Enter gameplay loop in Game
  • Game prompts the current player to make a move
  • Current player generates a move
  • That generated move is then passed back to the game, for the board to be marked.

Here is where the trade off arrives. My players all implement the interface Player. However, since the players are no longer responsible for marking the board directly they no longer need the board to be passed to them, except that some of them do…

Human Class

public int choosePosition(UserInterface ui, Board board) {
    return ui.getNumber();

DumbComputer Class

public int choosePosition(UserInterface userInterface, Board board) {
    return generateMove(board.availableMoves());

The situation here is that the Human class only really needs the UI passed to it, and the DumbComputer only really needs the board. However, in order to abide by LSP, I must keep the method parameters the same.

There are plenty of ways to think about this problem, but I cannot find one solution that beats all the others. I could for example pass the UI into the Human player’s constructor. Or the board into the DumbComputers constructor. The deliberation there is which one of those instances will be changing more often.

I could also consider that in reality, a Human player needs to “see” the board in order to make a move, and so passing the board to the Human isn’t that problematic anyway.

For now I think I’ll leave it, and then approach it again after some more features have been added, perhaps something else that’s added will affect how I approach this problem.