Design Patterns 101: Observer

There’s been some interesting discussion about the merits of the Observer design pattern recently and I thought that it would be a good idea to give a simplified explanation of what this pattern is and how it works for those who haven’t read the infamous “Gang of Four’s” book. We’ll use Xojo as the language for the explanation.

I’m working on a game engine at the moment, specifically the physics engine. Let’s say that in my game I want to support trophies (i.e: achievements) so that the player can be rewarded when they, well, achieve certain goals. One such trophy is “Go Stratospheric”. This’ll be awarded to the player whenever their acceleration exceeds a certain threshold value.

The thing about trophies is that you get given them for all sorts of things, not just events that can be detected by the physics engine. For example, you might get a trophy the first time you complete a level, etc. If we start hard-coding conditions into the game for when to award a trophy to the player we’ll find that our trophy code spreads like a cancer through our game. Sure “going stratospheric” does have something to do with our physics engine but it seems dirty to have an `awardStratosphericTrophy()` method call in the middle of the impulse resolution code of our physics engine .

Like all good programmers, we need to organise code to handle these kind of scenarios. This is a perfect example of where we can use The Observer Pattern.

Let’s take my example of giving a trophy to the player if their acceleration exceeds the `REALLY_FAST` threshold. Here’s a pseudo-snippet from the physics engine update code:

``````Sub UpdatePhysicsBody(b As Body)
b.Velocity = b.Velocity + someVelocity
If b.Velocity > REALLY_FAST Then
Notify(b, GOING_STRATOSPHERIC)
End If
End Sub
``````

All this code is saying is “If anyone cares out there, this particular `Body` in the simulation has just gone really fast”. With the Observer pattern our trophy system will register itself such that whenever the physics engine sends a notification, the trophy system receives it. The trophy system can then decide if the `Body` that is going really fast is the player. If it was, it’ll award the Going Stratospheric trophy to the player. All this is achieved without the physics engine giving two hoots about unlocks and trophies - all it cares about is vector maths, like a good little engine. In actual fact, if we decide later that we don’t want a trophy system anymore and we rip it out of our game, the physics engine doesn’t need to be altered at all.

Implementation

The implementation is really easy, it needs two participants: the `Observer` and the `Subject`.

The Observer

Any object that wants to know when something interesting happens to another object must implement our `Observer` interface.

``````Interface Observer
End Interface
``````

The `Observer` class interface has just one method that classes that use it must implement: `NotificationReceived()`. This takes two arguments: the object the notification relates to and an integer representing the type of event that occurred. You don’t have to use an integer (you could use a `String` or an `Enumeration`) but this will suffice for now.

Any class that implements the `Observer` interface becomes an observer. In this example, that’s our trophy system so let’s define a simple class to represent it:

``````Class TrophySystem Implements Observer
Select Case theEvent
Case GOING_STRATOSPHERIC
// Code for awarding the trophy goes here...
End Select
End Sub
End Class
``````

The Subject

The notification method is invoked by the object being observed. This is the subject. The subject has two jobs: (1) it holds an array of observers that are waiting to hear from it and (2) it’s responsible for sending notifications. We will implement this as another interface, this time called `Subject` that all subjects must implement if they want to be able to make notifications and have observers.

``````Interface Subject
Sub RemoveObserver(o As Observer)
Sub Notify(obj As Variant, theEvent As Integer)
End Interface
``````

Let’s change our physics engine to implement the `Subject` interface:

``````Class PhysicsEngine Implements Subject
// The actual physics code is omitted obviously!

// Create a private array to hold our observers.
Private MyObservers() As Observer

// Part of the Subject interface.
If MyObsevers.IndexOf(o) = -1 Then MyObservers.AddRow(o)
End Sub

Sub RemoveObserver(o As Observer)
// Part of the Subject interface.
// Remove this observer from our private array (if we know about it).
Var i As Integer = MyObservers.IndexOf(o)
If i <> -1 Then MyObservers.RemoveRowAt(i)
End Sub

Sub Notify(obj As Variant, theEvent As Integer)
// Part of the Subject interface.
// method and pass in the relevant information.
For Each o As Observer In MyObservers
Next o
End Sub
End Class
``````

Pretty simple eh?

I think you have a little error in there:

``````  Sub RemoveObserver(o As Observer)
// Part of the Subject interface.
// Remove this observer from our private array (if we know about it).
Var i As Integer = MyObservers.IndexOf
``````

should have the object reference after IndexOf

``````    Var i As Integer = MyObservers.IndexOf( o )
``````

I also prefer a little renaming as I find this easier to understand:

``````Interface iReceiver
End Interface

Select Case theMessage
Case GOING_STRATOSPHERIC
// Code for awarding the trophy goes here...
End Select
End Sub
End Class

Interface iSender
Sub Notify(Sender As Variant, theMessage As Integer)
End Interface

Class PhysicsEngine Implements iSender
// The actual physics code is omitted obviously!

// Create a private array to hold our receivers.

// Part of the Sender interface.
End Sub

// Part of the Sender interface.
// Remove this sender from our private array (if we know about it).
If rowIndex <> -1 Then MyReceivers.RemoveRowAt( rowIndex )
End Sub

Sub Notify(Sender As Variant, theMessage As Integer)
// Part of the Sender interface.