Design Patterns 2: The Observer Pattern

August 09, 2018

Observation Glasses

One big challenge for developers, especially in larger applications, is to avoid tight coupling between components. I had a great “real-world” example of tight coupling in my garden this summer. Some invasive vines got started among my tomato plants, and in about a week and a half had sent runners up and around the tomatoes. The vines had wrapped around the tomato plants numerous times, making the process of extracting them time consuming and difficult- after all, if I pulled the vines out without being careful I could damage my tomatoes!

If you’ve ever worked in an application where components were tightly coupled, you’ve felt this pain as well. Tight coupling of components is an enemy of good software design. Components should be built in a way that leaves a developer free to pull out, modify, and refactor them individually.

One design pattern that assists us in leaving our components loosely coupled is known as the “Observer Pattern”. In a nutshell, the Observer Pattern (another well-known variation of which is call the “Publisher/Subscriber or pubsub pattern) implements a one-to-many dependency between objects so that when there is a state change in a subject component, its observers are notified and updated. This means that relationships between components are kept manageable and flexible.

If you’ve worked with javascript for any amount of time, you’ve likely already implemented this pattern (possibly without knowing it). The element.addClickHandler() (or $(element).click() if you’re using jquery) is a perfect example of an observer pattern. A click on the element that the click listener is set on (the subject) will trigger a notification to be sent to its observers.

Let’s look at an example in code:

function Subject() {
    this.observers = [];  
}
 
Subject.prototype = {
 
    subscribe: function(observer) {
        this.observers.push(observer);
    },
 
    unsubscribe: function(observer) {
        this.observers = this.observers.filter(
            function(obs) {
                if (obs !== observer) {
                    return obs;
                }
            }
        );
    },
 
    fire: function(num) {
        this.observers.forEach(function(observer) {
            observer(`event ${num}`);
        });
    }

}

 
function run() {
    
    const respond = function(observer, event) {
      console.log(`${observer} responsing to ${event}`);
    }

    const observer1 = function(event) { 
        respond("observer 1", event)
    };

    const observer2 = function(event) { 
        respond("observer 2", event)
    };

    const observer3 = function(event) { 
       respond("observer 3", event)
    };
 

    const subject = new Subject();
 
    subject.subscribe(observer1);
    subject.fire(1);
	// "observer 1 responsing to event 1"
	
    subject.unsubscribe(observer1);
    subject.subscribe(observer2);
    subject.subscribe(observer3);
    subject.fire(2);
	// "observer 2 responsing to event 2"
    // "observer 3 responsing to event 2"

    subject.subscribe(observer1);
    subject.fire(3);
     // "observer 2 responsing to event 3"
	 // "observer 3 responsing to event 3"
	 // "observer 1 responsing to event 3"
     /* (note that since observer 1 was pushed
     onto the back of the array it is now firing last)*/
}

run();

The main difference between this pattern and the closely related “Publisher/Subscriber” pattern is that the Publisher-Subscriber uses a message channel layer in between the objects to further abstract out the relationship. In the observer pattern, the subject keeps a record internally of its observers, whereas a publisher object in the pub-sub pattern simply notifies a channel of events.


John D Potts

John D Potts

Web developer and speaker in Charlotte, NC.