Observer Pattern Explained Simply

Definition

The observer design pattern is a behaviorial design pattern in which you define a one-to-many subscription system between one object (known as the subject) to several other objects (known as the observers). The observer objects (or functions) ‘observe’ the subject and wait for some trigger from the subject before they perform an action.

This pattern might remind you of an event listener. This is probably because the observer design pattern is very useful and commonly used when it comes to creating event handling systems.

Real-World Example

A real-world example of the observer pattern on a high level is a YouTube channel. The YouTube channel is the subject. The YouTube channel can have multiple subscribers (observers) that get notified whenever the subject uploads a new video (the trigger).

Get Started

To get started, let’s create our subject:

function Subject()
{
    /**/
}

Cool. We’ve created our Subject object. Our subject needs to be able to keep track of all of the observer functions that are currently subscribed to it. How can we do that? We can store an array of observer functions in our Subject:

function Subject()
{
    this.observers = []; // array of observer functions
}


Now, let’s add a few methods to our Subject that will allow us to add and remove observer functions from the observers array. The first method we are going to add is subscribe(fn). subscribe(fn) takes in an observer function and adds that observer to the observers array:

Subject.prototype.subscribe = function(fn)
{
	// add a new observer function to our observer list
	this.observers.push(fn);
}


We’ve just added our subscribe method. Now let’s add the unsubscribe(fnToRemove) method which takes in the observer that we want to remove from the observer list. When we remove an observer from the observer list, that observer will no longer receive signals from the Subject.

Subject.prototype.unsubscribe = function(fnToRemove)
{
    // filter out 'fnToRemove' from our observer list
    this.observers = this.observers.filter( fn => {
	if(fn != fnToRemove) { 
	  return true;
	}
    });
}


unsubscribe(fnToRemove)filters out the observer function, fnToRemove, from the observers list. At this point we have our Subject which manages a list of the observers that are currently subscribed to it. We have a way to add a new observer to the list (subscribe) and a way to remove an observer (unsubscribe).

Now we need to create a method that sends a ‘trigger’ to the observers. How do we do that? Well, we can just loop through all of the observer functions in the observers array and call each function. Let’s create the method to do that. We’ll call this method trigger():

Subject.prototype.trigger = function()
{
    // for each observer function in our observer list...
    this.observers.forEach(fn => {
	// ...call the function
	fn()
    }
}


Bam! We are good to go! We now have our Subject constructor function that maintains an array of observer functions that are currently subscribed to it. Our Subject has the ability to add a new observer function to it’s list, remove an observer, and trigger a signal that will notify and call each observer. Let’s test it out!

Let’s create a new Subject:

const subject = new Subject();

Now let’s create a few observer functions:

function Observer1()
{
	console.log("Observer 1 triggered");
}

function Observer2()
{
	console.log("Observer 2 triggered");
}

Now that we have our subject and a few observers, let’s subscribe Observer1 to our subject. We can do this by saying:

subject.subscribe(Observer1);

We’ve just subscribed Observer1 to Subject. We’ve added Observer1 to the observers array. Now, whenever we send a trigger from Subject, the Observer1 function will be notified and will run:

subject.trigger();  // Observer 1 triggered

Remember, when we call trigger on our Subject, we loop through all of our current observers and call each of them:

Subject.prototype.trigger = function()
{
    // for each observer function in our observer list...
    this.observers.forEach(fn => {
	// ...call the function
	fn()
    }
}

Cool! So that works for one observer. Let’s try subscribing Observer2 as well.

subject.subscribe(Observer2);

And let’s send another signal from our subject:

subject.trigger();

The result will be:

"Observer 1 triggered"
"Observer 2 triggered"

So far we’ve:

  1. created a subject
  2. subscribed observers to our subject
  3. sent triggers from the subject to the observers

Now let’s try unsubscribing an observer from Subject. This will prevent that observer from receiving any more triggers from that subject. Let’s unsubscribe Observer1:

subject.unsubscribe(Observer1);

We have now removed Observer1 from the observersarray. Now, if we were to send another trigger, we should only see the message from Observer2:

subject.trigger(); // Observer2 is triggered

Summary

That explains the basics of the observer design pattern. The observer pattern is a design pattern in which you define a one-to-many subscription system between one object (known as the subject) to several other objects (known as the observers). The observer functions wait for triggers from the subject before performing an action.

If this article was helpful, tweet it!