As mentioned in a previous post, I've been working on a project that documents the various design patterns and approaches I use. This post is a continuation of that, which can be found in GitHub.

Additionally, I would also recomment reading the Head First Design Patterns book from O'Reilly. This book really makes design patterns stick in your head and help you to understand when one pattern is of benefit over another, and why. It's also formed the basis of my understanding of the patterns I'm covering in this series. So any imitation is purely a tribute to that book!

Overview

Let's start with a definition of the observer pattern:

The observer pattern defines a one to many relationship between an object, called the subject, and it's dependents, called observers. Such that when the subject changes it's state it's observers are notified.

Generally, speaking the Observer pattern involves a class design that uses Subject and Observer interfaces. You can also pass state in the notification from the Subject or you have have the Observer request the state after being notified of a change (as we'll cover later).

Code Examples

Now, let's run through some examples in code.

Scenario

The scenario we're going to use for this code example is that of a news station. The news station handles different types of headlines (in this case sports, current affairs and finance). We also have different types of reporters (yes, you guessed it one of sports, current affairs and finance). These reporters need to be notified when a new headline is created for their area of the news, to allow them to update their readers.

Overview

In the sample project (SJCNet.DesignPatterns.Observer) you'll see two folders, BasicAttempt and ObserverAttempt. The BasicAttempt details how I might attempt to resolve the problem without explicitly using the Observer Pattern.

In the code you'll see we have a NewsStationBase class which contains the logic for creating new headlines. This creates 5 new headlines at random intervals between 1 and 5 seconds. It's an abstract class and so is intended to be inherited from and the abstract NewHeadLineAvailable method is called each time there's a new headline. All pretty straight forward I hope.

Approach #1 - Basic Attempt

So, in the BasicAttempt code you'll see we have a NewsStation class, which inherits from the NewsStationBase class. The NewsStation class overrides the NewHeadlineAvailable method to implement it's own logic when a new headline is created.

In the NewHeadlineAvailable method we instantiate each of the types of Reporter and tell call their Report method passing in a headline (if one exists).

public class NewsStation : NewsStationBase  
{
    public override void NewHeadlineAvailable()
    {
        var sportsReporter = new SportsReporter();
        sportsReporter.Report(base.GetSportsHeadline());

        var currentAffairsReporter = new CurrentAffairsReporter();
        currentAffairsReporter.Report(base.GetCurrentAffairsHeadline());

        var financeReporter = new FinanceReporter();
        financeReporter.Report(base.GetFinanceHeadline());
    }
}

This approach has the following drawbacks:

  • We're coding to concrete implementations of the reporters. So the reporter classes are tightly coupled to the NewsStation class which means if any of the classes need to change, they may all need to change.

  • If we want to add another reporter, then we have to change the NewsStation class (another effect of tight coupling).

  • This is all pointing to the fact that we're not following the Open/Closed Principle.

Approach #2 Observer Pattern

In the ObserverAttempt folder you'll see the code I put together that in my opinion follows the Observer Pattern.

Here we have another NewsStation class that inherits from the NewsStationBase class. We've also added interfaces for ISubject and IObserver along with an IReporter interface (but that's not vital for the pattern).

The NewsStation class is the Subject so that implements the ISubject interface. This interface requires that the implementing class provides methods to manage the observers (namely RegisterObserver and DeregisterObserver) and a method to notify all observers of a change in state (NotifyObservers).

public interface ISubject  
{
    void RegisterObserver(IObserver observer);

    void DeregisterObserver(IObserver observer);

    void NotifyObservers();
}

The Reporter classes (namely SportsReporter, CurrentAffairsReporter and FinanceReporter) are the Observers so they implement the IObserver interface.

public interface IObserver  
{
    void Update(object sender);
}

The Update method is called by the NewsStation class when it notifys it's observers. The Reporter classes also implement the IReporter interface which exposes the Report method which is used to output the headline.

The main difference with this approach is how the Observers register with the Subject in the Example class.

var newsStation2 = new ObserverAttempt.NewsStation();  
newsStation2.RegisterObserver(new ObserverAttempt.SportsReporter());  
newsStation2.RegisterObserver(new ObserverAttempt.CurrentAffairsReporter());  
newsStation2.RegisterObserver(new ObserverAttempt.FinanceReporter());  
newsStation2.BeginBroadcasting();  

Another implementation decision I've taken is to not pass the change of state in the IObserver.Update method. Instead I've passed a reference to the sender (in this case NewsStation) so that the observers can pull the new state. I favour this approach because otherwise I would have to pass all different state changes to all observers, some of which may only care about a single state change. This way we can cast the sender to the INewsStation type and make the call to get the desired headline (e.g. GetSportsHeadline)

For me, this approach has the following benefits:

  • We have loose coupling between the Subject and Observers. Meaning the Subject doesn't need to know anything of the Observers other than the interface they implement. Additionally, the Observers don't need to know anything about the Subject other than it will call their Update method when there's a change in state.

  • It's trivial to add new Observers and we don't have to change the NewsStation class, we just have to register the new Observer with the Subject at runtime.

  • It's easier to test the Subject and Observer implementation.

Conclusions

This was a brief overview of the Observer Pattern. Hopefully it helps someone get some clarity on this very useful pattern!