Dwarves
Memo
Type ESC to close search bar

Introduce the Observer pattern and its use cases

Problem

Imagine that you have two types of objects: a Customer and a Store. The customer is very interested in a particular brand of product (say, it’s a new model of the iPhone) which should become available in the store very soon.

The customer could visit the store every day and check product availability. But while the product is still en route, most of these trips would be pointless.

On the other hand, the store could send tons of emails (which might be considered spam) to all customers each time a new product becomes available. This would save some customers from endless trips to the store. At the same time, it’d upset other customers who aren’t interested in new products.

It looks like we’ve got a conflict. Either the customer wastes time checking product availability or the store wastes resources notifying the wrong customers.

Concept of the Observer Pattern

Definition

The Observer pattern is a design pattern where an object, known as the subject, maintains a list of its dependents, called observers, and notifies them of state changes.

Real-World Analogy

If you subscribe to a newspaper or magazine, you no longer need to go to the store to check if the next issue is available. Instead, the publisher sends new issues directly to your mailbox right after publication or even in advance.

The publisher maintains a list of subscribers and knows which magazines they’re interested in. Subscribers can leave the list at any time when they wish to stop the publisher sending new magazine issues to them.

Examples

DOM Events and Event Listeners

In the browser, we use the Observer pattern through DOM events. The DOM element is the subject, and event listeners are the observers.

button.addEventListener('click', () => {
  console.log('Button clicked!');
});

Custom Event Emitters

We can create our custom event emitters to decouple code and enhance modularity.

const EventEmitter = require('events');
const emitter = new EventEmitter();
       
emitter.on('event', () => {
  console.log('An event occurred!');
});

emitter.emit('event');

In this example, emitter is the subject. When we emit the event, all registered observers get notified.

Redux: Leveraging the Observer Pattern

Redux is a state management library that uses the Observer pattern under the hood. The Redux store is the subject, and components that subscribe to the store are the observers.

const { createStore } = require('redux');
       
const reducer = (state = {}, action) => {
  switch (action.type) {
    case 'UPDATE':
      return { ...state, data: action.payload };
    default:
      return state;
  }
};

const store = createStore(reducer);

store.subscribe(() => {
  console.log('State changed:', store.getState());
});

store.dispatch({ type: 'UPDATE', payload: 'new data' });

Here, the store dispatches actions, and subscribed components get notified to update their state.

Pros & Cons

Pros:

Cons:

Reference