Observers and Observables
I’ve been making good progress with my Tic Tac Toe application in Java. I’m fairly happy with the Board, Game and MiniMax classes. But have been struggling with how to deal with the user interface. I had something working, but it was ugly and over-complicated. I knew there must be a better way of doing things but I wasn’t sure what.
The issue came to a head when I started to think about a Human vs Computer game, because I now needed to handle input from both a computer and human player. My first step was to have a separate class to handle each player type, so the HumanPlayer would request input from the terminal, whereas the ComputerPlayer would get the next move using the MiniMax class. The missing part was how to coordinate the HumanPlayer and the ComputerPlayer with the current Game.
In my research, I came across the Observer pattern, which is defined in this article as:
The observer pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
This looked very much like the problem I was trying to solve. With some further googling, I came across this article on Observer and Observable in Java, which walks through how the pattern works, and how to implement it in Java using java.util.Observer and java.util.Observable.
The essence of the pattern is that you have an object with state that will change (the Observable). When that state changes, it notifies any other objects which have subscribed to it (the Observers), that the state has changed.
The Observable can communicate changes in state to any subscribed Observers via a generic interface, which means the Observable doesn’t need to know anything about the Observers.
In my implementation the Game is the Observer and the HumanPlayer and ComputerPlayer are the Observers.
My Game class notifies changes in its start and move methods as follows:
Class Game extends Observable { ... public void start() {
notifyChange();
} public void move() {
[move logic]
notifyChange();
} private void notifyChange() {
// Call Observable method which sets flag that state changed
setChanged();
// Call Observable method with next player (i.e. X or Y)
notifyObservers(getNextPlayerSymbol());
} ...
}
My HumanPlayer and ComputerPlayer classes implement the Observer interface, which defines a single method update, which receives notifications from the Observer.
Class HumanPlayer implements Observer { ... public void update(Observable o, Object arg) { // Cast inputs to Game and PlayerSymbol
Game game = (Game) o;
PlayerSymbol playerSymbol = (PlayerSymbol) arg; // If game over then do nothing
if (game.isOver()) {
return;
} // If this player is the current player, then makeMove
if (playerSymbol == this.playerSymbol) {
makeMove(game);
}
} ...
}
All the moving parts are hooked up in my TicTacToeRunner buildGame method as follows:
private void buildGame() {
HumanPlayer p1 = new HumanPlayer(PlayerSymbol.X);
ComputerPlayer p2 = new ComputerPlayer(PlayerSymbol.O); Game game = new Game(); game.addObserver(p1);
game.addObserver(p2);
}
As you can see, the TicTacToeRunner is very simple, as it is just responsible for initialising the class instances and setting up the relationships.
As this setup has emerged, I have read into the MVC (“Model View Controller”) pattern. Whilst my classes have not adopted the MVC nomenclature, and I have not overtly tried to use MVC, the relationship between the various classes certainly seems to resemble MVC: the Game is the Model, the HumanPlayer and ComputerPlayer classes are the View and TicTacToeRunner is the Controller.
There are more challenges ahead. For example: how do I deal with starting a new game? But I’m starting to see the benefits of this approach and so will be looking into MVC in more detail.