design pattern

Behavioral Design Patterns: Observer

Today we’ll continue our journey through the Guide to Software Design Patterns series with a deep dive into the observer design pattern. The observer pattern is categorized as a behavioral design pattern, and its primary purpose is to allow a observer to “subscribe” to push-notifications generated by a provider.

In this article we’ll examine the observer design pattern by digging into both a real world example, along with a fully-functional C# code sample. By the end of this piece you should have a solid understanding of what the observer pattern is and how it can be implemented into your own code projects, so let’s get crackin’!

In the Real World

The observer design pattern consists of three main components:

  • Provider – Sends notifications of data to subscribed observers. It does so by keeping track of all subscribed observers.
  • Observer – Receives notifications of data from providers. Keeps track of received data so it can properly handle (and potentially ignore) data notifications that have already been received.
  • Data – The data that the provider is sending to observers via push-notification.

Paradoxically, it’s rather challenging to come up with a real world example of an observer pattern that doesn’t involve computing, because nearly every technological service or device we use on a daily basis implements an observer pattern in one way or another. App notifications on your phone or email alerts from your favorite shopping site are just two of the extremely common observer pattern scenarios many of us frequently experience.

One slightly less technical real world example of the observer pattern is when you sign up for a magazine subscription, such as WIRED (one of my personal favorites). While computers are obviously handling all the logic behind-the-scenes, the observer pattern is still being used in this case. You (an observer) have subscribed to a magazine provider. When the provider publishes a new issue (the data), you receive it in the mail a few days later. Critically, this is not a one-to-one relationship, in which the provider is sending the notification (magazine) only to you. Instead, they’re able to send it to thousands of people all at once, just as most digital services do when you sign-up for their email newsletter.

Full Code Sample

Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.

How It Works In Code

Our code sample uses the concept of news agencies like the Associated Press and Reuters. These agencies gather and create news reports from across the world, and then sell said reports to specific news organizations, such as newspapers and TV networks. To keep things a bit simpler, our sample code will encompass that relationship between just two news agencies (Associated Press and Reuters) and two newspapers (The Washington Post and The New York Times).

We’ve taken a handful of today’s top headlines from both agencies, and have created our example observer pattern code around the notion that these newspapers will subscribe (and possibly also unsubscribe) to said agencies, thereby receiving notifications of news stories as they’re published.

To achieve this we’ll start with the most basic object in the codebase, the Article class:

An Article is the basic form of data that an Agency will produce and publish, which sends it out to all subscribed observersNewspapers in this case. The Article class has some basic properties, though we’re foregoing the actual article content and just using the title and author to differentiate them from one another. We also want to know what Agency published said Article, so that property is also included. Lastly, we implement the IComparable interface so we can compare and sort Articles elsewhere in the code.

Next we have the Agency class, which acts as the provider in this example by publishing news Articles:

As previously mentioned, a provider should keep track of all its active observers, so the Agency definition begins with a list of Articles and observers, which are defined by implementing the IObserver interface.

The Subscribe(IObserver<Article> observer) method can be called by any IObserver<Article> object (such as Newspaper, which we’ll see in a moment). Doing so ensures that the observer is now tracked and will subscribe to all notifications created by this Agency instance. The Subscribe(IObserver<Article> observer) method also returns a new instance of Unsubscriber<Article>, which implements the IDisposable interface and allows the Dispose() method to be called, thereby releasing any unmanaged resources when invoked:

Back to the Agency instance methods, we’ll skip over CompareTo(object agency) since that’s self-explanatory. The Publish(string title, string author) method performs most of the logic when creating a new Article. It adds the Article to the local Articles list, then invokes the OnNext(Article article) method of all subscribed observers. We’ll look at this in a moment within the Newspaper class, but this method is required by the IObservable<T> interface and is the means by which observers are alerted of new data.

It’s also worth noting that we’ve elected to accept direct string parameters in the Publish(string title, string author) definition and used those to create a new local Article instance. This was done to simplify this code example, but in a real world scenario, it would likely be beneficial to create Article instances in an outside scope, and then pass them via a method signature like Publish(Article article).

The final method, Shutdown(), can be called if we want this Agency instance to halt all notifications and remove all current observers.

The last object in our observer design pattern trifecta is the Newspaper class, which acts as our observer entity and subscribes to Agency instances, in order to receive Article publications pushed via the Publish(string title, string author) method:

As an observer, the Newspaper class stores a list of Articles it has received, so it can avoid duplicates since an observer shouldn’t know (or care) when or how often a provider will push notifications out. It also maintains a SortedList<TKey, TValue> where TKey is Agency and TValue is IDisposable. This allows a Newspaper instance to subscribe to multiple providers (Agencies) at once, and when desired, unsubscribe only from the desired Agency (while maintaining other subscriptions).

As you may notice, Newspaper implements the IObserver<Article> interface, which requires that the following three methods be implemented.

OnCompleted(), which is invoked by the provider to indicate that it has stopped sending notifications:

OnError(), which indicates that the provider experienced an error. We’ve elected not to implement this method since no errors will be generated, but it’s required by the interface:

Finally, the OnNext(Article article) method, which is invoked by the provider when a new Article is published. This is the bread and butter of this class, and allows the observer to receive new data notifications:

Since Newspaper is an observer, we also need to implement some way for it to subscribe to providers (Agencies). The Subscribe(Agency agency) method allows the Newspaper to subscribe to the passed agency instance, by invoking the IDisposable Subscribe(IObserver<Article> observer) method within the Agency class and adding the IDisposable token to the local cancellations list for that Agency:

Similarly, we also have the Unsubscribe(Agency agency) method, which calls the Dispose() method of the cancellations list element for the passed agency. It also finds and removes all stored Articles that were produced by that Agency:

Whew! Now, with everything setup and ready to go, we can test this out by creating a few Agency and Newspaper instances, adding some subscriptions, publishing some articles, and seeing the results in the log output:

As you can see, we start by creating Agency instances for Associated Press and Reuters. We also create Newspaper instances for The New York Times and The Washington Post. Before we examine it any further, let’s jump ahead a bit and look at the output from executing the code above, which we’ll reference as we go through the remainder of the NewsTest() method:

Even though the next line of our method has associatedPress publishing an article by Juliet Linderman, our output doesn’t display that article anywhere. This is because neither of our Newspaper instances have subscribed to associatedPress at this point. This illustrates how the observer pattern is ignorant of the relationships behind-the-scenes. It doesn’t care who is subscribed, it just pushes notifications and those who happen to be listening will receive them.

Anyway, the next section of code has newYorkTimes subscribing to associatedPress, along with washingtonPost subscribing to reuters, both of which are reflected in the output log:

reuters then publishes two Articles and, now that it has subscribed, washingtonPost receives both of those notifications:

Similarly, associatedPress publishes two Articles of its own, which newYorkTimes receives:

The washingtonPost then subscribes to associatedPress as well, followed by two more publications from associatedPress. Now that associatedPress has two subscribers, we should see two outputs for each Article published:

The washingtonPost has now elected to unsubscribe from associatedPress, just before associatedPress publishes one last Article. Both these events are shown in the log, with the last article only being picked up by the remaining observer (newYorkTimes):

Finally, reuters publishes three more Articles, and we illustrate that the washingtonPost observer can remain subscribed to an Agency even after leaving another, since it receives all three notifications:

There you have it! Hopefully this article provided a bit of insight into the capabilities of the observer design pattern, and gave you some basic tools you can use in your own future projects. For more information on all the other popular design patterns, head on over to our ongoing design pattern series here!