Yesterday we saw the Strategy Pattern. Today I want to talk about the Observer Pattern.

I got a bit of a mixed feeling about this pattern, since in the .NET world, we got events and delegates making this pattern somewhat unneeded.

However, it's good to know how it works, since it's used behind the scenes in the .NET CLR when working with events. Besides, better know too much than too little, knowledge is power.

Also, I'm planning to write a separate post after this to go into the C# specific implementation anyway.

First, the definition again: "Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically."

Let's continue with our example from yesterday, were we made an object model to describe some game characters. The next requirement came in, and we need to display movement of our units on the screen.

Initially, we are given one screen, a big overview of a battle map, where all units are displayed on and move around on.

An easy quick approach would be to simply add some coordinates information to our GameUnit class and add in a Move() method which gets called whenever the unit moves.

This Move() method would then simply call our BattleMapDisplay class to inform it of its new location.

Quick Hacky Notification

That would work, for now... But what if we want to add in a different type of display?

Let's say we want to add in a OverviewDisplay as our main view. Then we have to go and change our GameUnit class to inform this screen as well. Bad. Let's fix this up a little.

If we look at it from a higher level again, all our displays are doing is observing our game units and acting upon any change in them. So, one display is actually an Observer of our GameUnit, the Subject. And there we have it, our displays have a one-to-many relation with a GameUnit and want to be notified when it changes it state, the Observer Pattern's exact definition. :)

Remember from last time? Program to an interface, not an implementation.

When we set up a system to let objects communicate state changes to each other, the only thing these objects should know about each other is a common communication interface. Let's create that one by adding two additional interfaces, IObserver and ISubject.

Notification Interfaces

Now that we have our new interfaces, we can change the GameUnit class to hold a collection of IObserver objects. Together with providing two methods for additional observers to subscribe themselves so they can get notifications when the GameUnit changes.

By implementing it this way, we can easily add new displays or other objects to our application, which can easily stay informed about our units as long as they implement the IObserver interface and subscribe themselves with the units.

The GameUnit doesn't care about which kind of object is on the receiving end of the notification, and so won't have to be changed whenever an new Observer is added. The Observer however will have to make checks in its Update() method to determine which ISubject is being returned.

Observer Pattern

Whenever a GameUnit moves right now, it informs all screens about this, passing itself along so the observers can get information out of the object.

And that's it really, the Observer Pattern isn't all that hard, it's a simple notification mechanism. In a next post I'll talk more about delegates and events to have a look on how the Observer Pattern is implemented in the CLR.

If you have any questions about this pattern, please leave them in the comments, something you want to know, something I overlooked or was unclear about, just ask, it's from having a dialog we learn the most.

As usual, I uploaded the solution I used for this post so you have a detailed look at the code used.

Some additional information on the Observer pattern:

Comments: 1
  • austin a

    Your series is very helpful. Rather than conceptual and theoretical you give a simple example where the design benefits from using that design pattern.

    I especially like how you point out future pitfalls of using an approach that doesn't use that design pattern. Well done.

  • Leave a reply
    Items marked with * are required. (Name, Email, Comment)
    Comment is missing some required fields.
    To make sure you are not a computer, please type in the characters you see.