Post

The Observer Pattern

The Observer pattern is very useful when you have several classes (the observers) that depend on changing data in a specific class (the subject). (For other design patterns, see Why Know Design Patterns?)

Definition

The Observer Pattern defines a one-to-many-dependency between objects so that when one object changes state, all its dependents are notified and updated automatically1

The “one” in the “one-to-many-dependency” is the subject, or in other words, the object being watched. The “many” are the observers, who want to be informed when something in the subject changes.

Why use the Observer pattern?

As is clear from the wording of the definition and the first sentence of this post, the observer pattern has to do with dependency. That is, the observers (the classes that need to know about data that’s changing) are dependent on the subject because that’s where the data changes. It would be very inefficient for the observers to constantly poll the subject for this information. Rather, we would only want some action if there actually are changes to be notified about (which means we want to be reactive).

At the same time, we don’t want to create a dependency between these objects by hardcoding the observers into the subject’s code. That would mean we have to keep on making changes to the subject when the main function of the subject hasn’t changed - meaning we could introduce several bugs to areas where we don’t even need to introduce change - possibly affecting all the other observers too (and the house of cards comes crashing down)!

What we do in the Observer pattern instead is to define an interface that all observers should adhere too (with an Update() method), and then keep a list of objects implementing that interface in the subject.

1
2
3
4
public interface IObserver
{
    public void Update();
}

We have some way of registering (and deregistering) an observer with the subject, so that the observer gets added to the list (through an interface that the subject implements, with a Register() method).

1
2
3
4
5
public interface ISubject
{
    public void Register(IObserver observer);
    public void Deregister(IObserver observer);
}

But the subject doesn’t actually know much about the observer, only that that observer (like all others) implements the Update() method defined in the interface. When data changes, the subject goes through the whole list of observers and run their Update() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Subject: ISubject
{
    private List<IObserver> Observers { get; set; } = new List<IObserver>();
    // more properties, just like any other class

    public void Register(IObserver observer)
    {
        Observers.Add(observer);
    }

    public void Deregister(IObserver observer)
    {
        Observers.Remove(observer);
    }

    // some method to get information, if necessary

    public void SomethingHappened()
    {
        // some change in data happened, let all the observers know!
        foreach (var observer in Observers)
        {
            observer.update();
        }
    }
}

Using the Observer pattern in C#

I’ve added an example implementation of the Observer pattern in a simple console application project here. The example has a Player as the subject, and a ScoreWatcher and RatingsWatcher as observers. When the Player gets updated (done manually in Programs.cs), the Player notifies the Watchers and they, in turn, request the new information from the Player. This is a “pull” configuration - the Player could also have “pushed” information to the Watchers by immediately supplying them with information. But in this case, extra information would be going to the observers that they might not need. By pulling, they can get only the information that they are interested in.

This illustrates how the design pattern works. However, there are two built in C# implementations of the Observer pattern that you should use instead.

The first of these is IObservable<T> / IObserver<T>, which implements a push-based notification system. The second is EventHandler. EventHandler uses objects called Events to carry the information to the observers - see Handle and raise events.

Footnotes

  1. Freeman, Eric & Elisabeth Robson. 2021. Head First Design Patterns: Building Extensible & Maintainable Object-Oriented Software, 2nd Edition. O’Reilly. Page 51. Slightly different wording in Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. 1994. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional. Page 293. 

This post is licensed under CC BY 4.0 by the author.