Observer Design Pattern — Explained In Five Minutes

Animesh Gaitonde
The Startup
Published in
7 min readJan 2, 2021

Implementation & Illustration of the Observer design pattern

Art of Observing

Introduction

Real-world software systems rely heavily on events. Any state change occurring in the system comprises an event. Whenever you purchase anything online, you get an email notification. Similarly, your Bank may send you a text message about a successful transaction. As customers, we have different modes of consuming these events viz Computers, Mobile Devices, Wearables, etc. Billions of such events take place throughout the world in a fraction of a second.

The Observer design pattern is modeled on the event-driven programming paradigm. Just like other design patterns, this pattern lets us define loosely coupled systems. Leveraging this pattern, we can write maintainable and modular software. Additionally, we can achieve clear segregation between different actors in an event-driven system.

Real-World Analogy

Let’s say that you like watching youtube videos or binge-watching Netflix shows. There may be one channel that might have caught your attention on youtube. Or you may be eager to watch the next season of TV Series, that’s yet to be released. What would you do to watch the next video/season of the TV show?

A simple solution is to repeatedly open the app/webpage and check if the new content is uploaded. But, this would be cumbersome for the user. The user would waste a lot of time in checking for any update on the website.

Check the website for new content

To overcome this, the website may send an email notification to every other user whenever any new content is posted. But there are thousands of new videos or shows uploaded every day on the website. And many users may not be interested in receiving notifications about every other show. This would result in spamming the user’s inbox and eventually resulting in chaos.

Send Notification to everyone

Real-World Solution

The above problem can be solved by sending a notification to only interested customers. Netflix has an option called “Remind me”. As soon as new content is uploaded, Netflix will send you an email. In case you change your mind, you can remove the reminder. On Youtube, you can click on the Bell icon and subscribe to a channel. When a new video is added, all the subscribers get a notification.

Remind Me on Netflix
Youtube Bell-icon

This forms the basis for the Observer design pattern. Fundamentally, we use an observer when a state change has to be communicated to a list of entities. The entities may wish to subscribe or unsubscribe to certain state changes. We will take a deep dive into this pattern in the subsequent sections.

Why Observer?

Before diving into the intricacies of the Observer design pattern, let’s understand why it’s needed? Assume that you are designing a stock market platform. The platform consumes the latest market data and displays the last traded price and percent change from the last close price. For simplicity, let’s develop a console app.

Sample market Book

As shown in the above pic, your system needs to display LTP (Latest Trade Price) and CHNG (% Change). For every trade, an event would be sent containing the trade data. We will start with a naive implementation of the above.

We will create two concrete classes to fulfill our functionality a) PercentChangeDisplay and b) LatestTradePriceDisplay. These two classes are display elements and will print the data on the console. Further, we will introduce a class StockMarketDataHandler, which will act as a source of market data events. This class will hold a reference to the display elements. Following are the code snippets & output after executing the code:-

LatestTradePriceDisplay
PercentChangeDisplay
StockMarketDataHandler
Main
Output

Following is the UML diagram:-

UML Diagram of the system

Let’s see what are the limitations of the above code:-

  • It violates the Open/Closed principle. We haven’t declared an interface or a contract for communicating the state changes. Currently, there is a hard dependency on the method process market data()
  • The code is not extensible & it’s difficult to factor in new requirements. What if there is a new requirement to display the Average price or Volume. Similar to PercentChangeDisplay and LatestTradePriceDisplay, we would add the corresponding classes. Further, we would have to modify the existing class to delegate the processing of market data to the new classes
  • There is a tight coupling between StockMarketDataHandler and the two concrete classes. Addition of new features would mean adding more classes in the constructor parameter
  • Removal of a feature would also result in modification of the class StockMarketDataHandler. For eg:- To stop the display of PercentChange, we will have to remove the class PercentChangeDisplay

How the Observer solves this problem?

The design pattern defines two entities a) Subject or the Publisher b) Observer or Subscriber. The Observer is an entity that reacts to events or notifications. The Observer registers with the subject to consume events. It has the ability to deregister and thereby stop consumption of the events. A Subject manages all the state changes and communicates the same to all the observers. We use this pattern whenever state changes are to be communicated to multiple objects.

We will now construct the contracts of Observer and the Subject. We declare an interface for the Observer. The Subject uses this interface & passes the events to the subscriber. In the above example, we can abstract the method processMarketData() in an interface. The concrete classes PercentChangeDisplay and LatestTradePriceDisplay will then implement this interface. The two classes have been renamed to PercentChangeObserver and LatestTradePriceObserver. Following will be the code changes:-

MarketDataObserver
LatestTradePriceObserver
PercentChangeObserver

Now, we will make changes to the Subject StockMarketDataHandler. It will hold a reference to a list of observers. For handling an event, it will iterate on the list and delegate the call to every observer. Additionally, it will provide methods to subscribe and unsubscribe the observers.

StockMarketHandler

Finally, let’s look at the runner code.

Main

Below is the UML Class diagram for the Observer design pattern.

Observer UML Diagram

Benefits of using Observer

  • Extensibility- It can be seen from above that the addition of a new feature, will result in the introduction of a new concrete observer. We can then subscribe or unsubscribe this observer from the subject. Further, the functionality of new observers can be tested independently in isolation
  • Loose Coupling- From the above diagram, it’s clear that the subject doesn’t need to know the internal details of the observer. The subject only relies on the interface to communicate the events to the observers. Hence, the subject and observer classes are loosely coupled
  • Open/Closed principle- The subject class is now closed for modification. The addition of a new feature doesn’t result in any change in the subject class. Only new observers need to be implemented and added in the subject

Conclusion

The observer design pattern is useful in designing event-driven systems. The pattern is extensively used in GUI programming and user interfaces. Furthermore, certain background or timer-based jobs also implement the observer pattern. The mediator design pattern bears some resemblance to the observer.

Thanks for reading the article! Before you go:

References:-

--

--

Animesh Gaitonde
The Startup

SDE-3/Tech Lead @ Amazon| ex-Airbnb | ex-Microsoft. Writes about Distributed Systems, Programming Languages & Tech Interviews