📓
Design Patterns & Principles
  • Recipes: Design Patterns And Principles
  • Design Patterns
    • Singleton Pattern
    • Module Pattern
    • Observer Pattern
    • Decorator Pattern
    • Factory Method Pattern
    • Builder Pattern
    • Adapter Pattern
    • Bridge Pattern
    • Composite Pattern
    • Facade Pattern
    • Flyweight Pattern
    • Proxy Pattern
    • Chain of Responsibility
    • Command Pattern
    • Iterator Pattern
    • Mediator Pattern
    • Memento Pattern
    • Visitor Pattern
    • Strategy Pattern
    • State Pattern
    • Template Method Pattern
    • Prototype Pattern
  • Software Principles
    • SOLID Principle
    • DRY Principle
    • Software Architecture Fundamentals
      • Architecture Style
        • Service-Oriented Architecture (SOA)
Powered by GitBook
On this page
  • The Observer with the update function
  • Unsubscribing to prevent the lapsed listener issue
  • Adding TypeScript to our Observer
  • Resources

Was this helpful?

  1. Design Patterns

Observer Pattern

The Observer pattern is common among various native JavaScript features and many libraries. In this part, we learn the principles of the Observer pattern.

PreviousModule PatternNextDecorator Pattern

Last updated 4 years ago

Was this helpful?

The core principle of the Observer pattern is defining a mechanism of subscription to notify various objects about events. The notified objects have to explicitly state that they are interested in the above events first. The above is a common situation in JavaScript. We sometimes have some libraries taking care of the above tasks. On the other hand, it might be beneficial to know how it works under the hood.

The subject holds a list of observers and calls every one of them in case it wants to communicate something.

class Subject {
  observers = [];
}
class Subject {
  observers = new Set();
}

The Observer with the update function

There are a few approaches that we can take. The first of them includes creating an Observer class.

Our Observer class contains the update method. Let’s now expect every Observer to implement it. With that knowledge, we can continue writing the Subject class.

Since now we expect every Observer to implement the update method, we call it when we want to notify our observers.

class Subject {
  observers = new Set();
 
  subscribe(observer) {
    this.observers.add(observer);
  }
 
  notify(message) {
    this.observers.forEach((observer) => {
      observer.update(message);
    })
  }
}
const subject = new Subject();
 
subject.subscribe(new Observer());
subject.subscribe(new Observer());
 
subject.notify('Hello world!');

Hello world!

Hello world!

Thanks to using a Set, we don’t have to worry about duplicates when subscribing. Therefore, they will be omitted.

new Observer() === new Observer() // false
const subject = new Subject();
 
const observer = new Observer();
subject.subscribe(observer);
subject.subscribe(observer);
 
subject.notify('Hello world!');

Hello world!

Since above we subscribe using the same observer twice, it is added only once.

The thing left to implement is the unsubscribe method.

unsubscribe(observer) {
  this.observers.delete(observer);
}

Unsubscribing to prevent the lapsed listener issue

If you want to know more about the garbage collector check out those two articles:

Adding TypeScript to our Observer

Expecting the Observer to have the update method or to be a function is a rather bold assumption. It is a very fitting place to introduce TypeScript. First, let’s define the basics of our Observer:

Above, we demand that every observer implements the update method. We don’t enforce the message type here, so we leave it as any.

We use the above interface in our Subject class.

class Subject {
  private observers = new Set<Observer>();
 
  subscribe(observer: Observer) {
    this.observers.add(observer);
  }
 
  unsubscribe(observer: Observer) {
    this.observers.delete(observer);
  }
 
  notify(message: string) {
    this.observers.forEach((observer) => {
      observer.update(message);
    })
  }
}

The essential thing above is that the Subject accepts any Observer as long as it has the update method.

class MyObserver implements Observer {
  update(message: string) {
    console.log(message);
  }
}
const subject = new Subject();
 
const observer = new MyObserver();
subject.subscribe(observer);
 
subject.notify('Hello world!');

The above approach makes our Subject highly reusable and generic while making sure that the update function is there.

class MyObserver implements Observer {
  hello() {
    console.log('Hello world!')
  }
}

Class ‘MyObserver’ incorrectly implements interface ‘Observer’.

Property ‘update’ is missing in type ‘MyObserver’ but required in type ‘Observer’.

Resources

There are a few things to consider when designing a list of observers. Let’s assume that we want it to have no duplicates. The second thing that we want to provide is a straightforward way to unsubscribe from the list of observers. A better candidate than an array to implement the above features is a .

The object lets you store unique values of any type, whether primitive values or object references

An important note is that a looks at object references when checking for duplicates. Even though we added two identical observers, they are two different objects.

The same thing applies to the function of a Set. Therefore, our unsubscribe function needs to be provided with the same object in order to delete it.

Class Diagram - Observer Pattern

Remember always to unsubscribe if you don’t need the observer to listen anymore. Forgetting to do so prevents the observer from being garbage-collected. This is an issue that we call the . A solution to the above problem might be using the instead of Set, but it doesn’t allow us to iterate its elements.

Set
Set
Set
delete
lapsed listener problem
WeakSet
Understanding memory management and the garbage collector
Making the job of garbage collector easier by replacing the Map with the WeakMap
JavaScript design patterns #5. The Observer pattern with TypeScriptMarcin Wanago Blog - JavaScript, both frontend and backend
Observer Pattern | Set 1 (Introduction) - GeeksforGeeksGeeksforGeeks
Logo
Logo