# Observer Pattern

![](https://res.cloudinary.com/practicaldev/image/fetch/s--4S45AY28--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/i/0umqa0oz6wf95h6aza4j.jpeg)

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 = [];
}
```

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 [**Set**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).

```
class Subject {
  observers = new Set();
}
```

> The [**Set**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) object lets you store unique values of any type, whether primitive values or object references

### 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!&#x20;
>
> Hello world!

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

An important note is that a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) looks at object references when checking for duplicates. Even though we added two identical observers, they are two different objects.

```
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);
}
```

The same thing applies to the [*delete*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) 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](https://www.geeksforgeeks.org/wp-content/uploads/o2.png)

### Unsubscribing to prevent the lapsed listener issue

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 [lapsed listener problem](https://en.wikipedia.org/wiki/Lapsed_listener_problem). A solution to the above problem might be using the [WeakSet](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) instead of Set, but it doesn’t allow us to iterate its elements.

> If you want to know more about the garbage collector check out those two articles:
>
> * [*Understanding memory management and the garba*ge collector](https://wanago.io/2018/06/25/understanding-memory-management-and-the-garbage-collector/)
> * [*Making the job of garbage collector easier by replacing the Map with the WeakMap*](https://wanago.io/2019/08/19/map-and-weakmap/)

### 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’.&#x20;
>
> Property ‘update’ is missing in type ‘MyObserver’ but required in type ‘Observer’.

### Resources

{% embed url="<https://www.youtube.com/watch?v=_BpmfnqjgzQ&ab_channel=ChristopherOkhravi>" %}

{% embed url="<https://wanago.io/2020/01/20/javascript-design-patterns-observer-typescript/>" %}

{% embed url="<https://www.geeksforgeeks.org/observer-pattern-set-1-introduction/>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://altafshaikh.gitbook.io/design-patterns-and-principles/design-patterns/observer-pattern.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
