Suppose you have just ordered a meal at a food place with a 4.8 stars rating on Google. The cashier tells you the order might take awhile, and passes you a buzzer, which will vibrate and sound when your food is ready. As the food place is situated within the mall, you decided to walk around first while waiting for your food.
With the buzzer, instead of having to constantly check whether your order is ready and staying in the restaurant, you can now return back only when the buzzer sounds.
The scenario above is somewhat similar to the observer pattern—the customer is notified when the restaurant is ready to serve the food, instead of having to constantly check on the restaurant. We'll elaborate more on this later.
The Observer Pattern is a design pattern used typically for event-driven software architectures. Specifically, it can be used for objects that depend on another object's state changes.
There are two main components that drive the observer pattern—1) the observer, and 2) the subject.
The observer, as the name suggests, observes a subject and is notified by the subject when a particular event occurs. On the other hand, the subject notifies the observer when a particular event occurs. This can be illustrated by the following UML class diagram, that outlines some basic methods both observers and subjects have:
The class diagram shows that the subject maintains a list of observers subscribed to it so that it will be able to notify this list of observers when the event occurs. Note that each subject can have many observers, demarcated by the asterisk beside the Observer interface.
The main rationale behind using the Observer pattern is to allow for multiple observers to subscribe to a particular subject. Examples include when multiple UI components are listening for user action, or are waiting for some data to be fetched by the subject in order for them to perform some computation accordingly.
To mitigate the effect of tight coupling, an Observer interface is created so that the Subject does not need to manage each concrete Observer individually.
A specific instance when the Observer pattern is used could be the food collection system in a restaurant, in the example raised earlier:
Buzzer class implements the
Observer class, and subscribes to the
OrderHandler class. The
OrderHandler class would implement the
Subject class, which notifies all subscribers when a particular order is ready. We can also consider another
WaitStaff class, which models wait staff who will be notified when dine-in orders are ready to be served to customer. In this case, we have multiple
Observers subscribing to the
One benefit of using the Observer Pattern is potentially the improved reactivity of your application. Instead of constantly checking on the subject, or being blocked by waiting on the event to occur on the subject, the observer gets notified only when the event occurs, and can free up its resources to continue with other work instead of constantly checking on the subject.
In the analogy given earlier, with the buzzer that notifies the customer, the customer doesn't have to constantly check for the order and is able to do other things.
You could for example, set the observer to listen for the event outside of the main thread, and do other work on the main thread. In observer pattern libraries like ReactiveX, the observer can observe the subject on a specified thread, which prevents blocking of other processes that need to run on the main thread .
During my internship as an Android engineer at Ninja Van, I found myself having to use the Observer pattern in various aspects of Android development — from observing the UI for changes, to observing the database for any output to update the UI.
The team made use of Android's in-build LiveData class, which loosely help developers to implement the Observer pattern. The
LiveData itself is an observable data holder class , similar to a
Subject, and can be bounded to UI elements, which are the
Observers will update themselves on
LiveData updates and notification.
The use of the Observer pattern is particularly important in Android. This is because the main thread is used for rendering UI , so actions such as synchronously accessing the database should be avoided, and instead we can get the UI to observe the ViewModel for any data retrieval event, so that we could update the UI accordingly.
There are also other libraries supporting the Observer pattern, such as ReactiveX, which is also used by my team to better support the subscription needs of various classes. It is also used to notify UI components when data is being retrieved from persistence via a non-UI thread. However, the use cases of ReactiveX span beyond the Observer pattern, which is perhaps a topic for another day.
The Observer pattern can be incredibly useful for MV* architectures, where UI components are heavily dependent on the data. But note the risks that come with it, so use it wisely!
 ReactiveX - Scheduler: http://reactivex.io/documentation/scheduler.html
 LiveData Overview: https://developer.android.com/topic/libraries/architecture/livedata
 Processes and threads Overview: https://developer.android.com/guide/components/processes-and-threads