Skip to content

Observer Pattern Exercise

Info

This exercise is based on a simple implementation of the SpaceInvaders game.

Problem

The ScorePanel is updated by the Application class every time the timer ticks. We want to change this situation so that ScorePanel is only updated when a change in the game warrants it (e.g., the number of invaders or missiles changes, or a new game starts).

Consider how to implement this functionality using the Observer design pattern.

Note

Solution

We need to decide "who" is the observer, and "who" is the subject of observation.

ScorePanel is the observer of the events in the game. The game events are managed in the controller class SpaceInvaderGame. So, ScorePanel must implement Observer interface and SpaceInvaderGame (which is the subject of observation) must extend the Observable class.

Next, identify the observable behavior in the subject (some behaviors that change the state, that you want the observers to be updated about; such behavior is called the trigger point).

There are several methods in the SpaceInvaderGame that can be considered as a trigger point; essentially any method that updates the number of missiles or the number of invaders in the game must be considered a trigger point.

Next, call (setChanged() and) the notifyObservers() method from the trigger point method.

Here is an example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// fires a missile if max number of missiles in play has
// not been exceeded, otherwise silently returns
private void fireMissile() {
    if (numMissilesInPlay < MAX_MISSILES) {
        Missile m = new Missile(tank.getX(), tank.getY());
        sprites.add(m);
        numMissilesInPlay++;
        setChanged();
        notifyObservers();
    }
}

Next, decide how the observers are going to react to the notification (override the update method in each concrete observer)

Here is a sample implementation of update in ScorePanel:

1
2
3
4
5
6
7
8
@Override
public void update(Observable o, Object arg) {
    SpaceInvaderGame game = (SpaceInvaderGame) o;
    invadersLbl.setText(INVADERS_TXT + game.getNumInvadersDestroyed());
    missilesLbl.setText(MISSILES_TXT + 
        (SpaceInvaderGame.MAX_MISSILES - game.getNumMissiles()));
    repaint();
}

Finally, register the Observers with the Subject calling addObserver().

In the Application constructor, you can add the following:

1
game.addObserver(scorePanel);

Info

Download the refactored SpaceInvaders.