Design Patterns in Action(8)- Observer

A series of programming design patterns illustration with examples with JavaScript/Python

Photo by Road Trip with Raj on Unsplash

Simply put, the Observer pattern offers a Publication/Subscription model where observers subscribe to an event and get notified when the event happens.

It is one the most important models in event-driven architecture. Essentially it has 2 participants, the observer(s) and the observable.

Observable:

  • links to one event type
  • maintains list of observers
  • supports subscribe or unsubscribe from the observers.
  • notifies observers when its state changes (events come in)

Observers:

  • subscribes/unsubscribes from the observer based on event topics.
  • implements a function signature that will be invoked by the observable when an event occurs.

Note that the Observer pattern, even implementing a pub/sub model, is not strictly equal to Publish/Subscribe pattern, as the latter actually moves the broadcasting stage out of the Publisher’s internal state to an external event channel (often using Queue), comparing to the Observer(Subscriber) to be notified by the Publisher itself directly. This further decouples the dependencies between the Publisher and Subscriber, and demonstrates loose coupling.

First, let’s see an example in Python:

Now an example of JavaScript, note the use of set , so it’s safe for us if we accidentally passing in the same observer for multiple times as set checks for reference. Also note this way we are passing in the function directly as observer just as the everyday JavaScript event listener you will see on the browser: window.addEventListener(‘click’, () => {console.log(‘Page loaded’)});

Sometimes we want to have more control of the observer, or just have another way of implementing this. In this way, we have an agreed contract between the Observable and the Observer on the update method. And instead of invoking the observer directly, we will trigger the update method on the observer.

You can also combine state management in this, to initiate a state object at Observable initiation, and every time a new piece of data passed in, we merge it with the existing data object, and pass this merged data to the observers.

Also, always remember to unsubscribe the observer from the observable when it’s no longer in use, as failing doing so will cause the observer not being garbage collected, aka. the lapsed listener problem .

Another feature that is common in real life scenarios that we haven’t implemented in the blog is the ability to pass in a scope variable. So instead of just passing in the data, we can pass in a scope to decide the this of the observer. This happens a lot in event listeners, when the scope is normally bounded to a global object e.g. window if not overwritten.

That’s so much of it! Happy Reading!