DEV Community

Cover image for JS and Design Patterns - Chapter 4 ๐Ÿš€
devlazar
devlazar

Posted on • Updated on

JS and Design Patterns - Chapter 4 ๐Ÿš€

Table Of Contents
* ๐Ÿค“INTRODUCTION
* ๐Ÿ‘€ABOUT OBSERVER
* ๐Ÿฆ„ENTITIES
* ๐ŸŒ REAL WORLD ANALOGY?
* ๐Ÿ“ฐNEWS ANALOGY
* ๐Ÿ“ˆ STOCK ANALOGY
* โ“ WHEN TO USE?
* โš™ RxJS applicability
* โœ…PROS
* โŒCONS
* ๐Ÿ™THANK YOU

๐Ÿค“ INTRODUCTION

Hello, codedudes and codedudettes, I hope you are having a great day! Let's make it even better, let's learn something new. Software development is a neverending story where you always learn something new, personally, I always push myself to do the best and to learn as much as I can. But remember, don't overwork yourself!

Today, we are talking about a very popular design pattern, The Observer Pattern.

Observer

๐Ÿ‘€ ABOUT OBSERVER

The Observer Pattern is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they're observing. In other words, the Observer Pattern defines a one-to-many type of dependence between different objects, and it ensures that the change of the state in one object gets automatically reflected in all dependant objects!

๐Ÿฆ„ ENTITIES

Entities that will participate in the Observer paradigm are:

  • SUBJECT It keeps a reference towards its observer. One object can have many Observer objects It provides an interface for "attaching" and "detaching" observer objects
  • CONCRETE SUBJECT It keeps the state of interest of the Concrete Observer objects It sends notifications to its observers when the state changes
  • OBSERVER It defines an interface for updating the objects after the state of the changes in the objects of the class type Subject
  • CONCRETE OBSERVER It keeps a reference to the Concrete Subject objects It keeps the state that should stay consistent with the state of the parent class It implements an interface for updating object that is defined in the Observer class

Let's see the code ๐Ÿ‘ฉโ€๐Ÿ’ป (โ— And as always, read the comments ๐Ÿ˜Š)

Observer1

//The subject class
//It provides an interface
//for "attaching" and "detaching" 
//observer objects
class Subject{
    constructor(){
        this.observerList = [];
    }
    attach(observer) { 
        console.log(`๐Ÿ“Ž Attaching observer... ${observer.name}`);
        this.observerList.push(observer);
    }
    detach(observerId) {
        let observer = this.observerList.find(item => item.id === observerId);
        console.log(`๐Ÿ”— Detaching observer... ${observer.name}`);
        this.observerList = this.observerList.filter(item => item.id !== observerId)
    }
    notify() { 
        console.log('๐ŸŸขThe Notification process starts...');
        for (let i = 0; i < this.observerList.length; i++) {
            this.observerList[i].update()
        }
        console.log('๐Ÿ”ดThe Notification process ends...');
    };
}
//It keeps the state of interest of the Concrete Observer objects
//It sends notifications to its observers when the state changes
class ConcreteSubject extends Subject {
    constructor(){
        super();
    }
    //return subject state
    getSubjectState(){ return this.subjectState; }
    //set new subject state
    setSubjectState(subjectState){ this.subjectState = subjectState; }
    function(){
        return { getSubjectState, setSubjectState }
    }
};
//It defines an interface for updating the objects after the state 
//of the changes in the objects of the class type Subject 
class Observer{
    update() { return; }
};
//The concrete observer class will extend an observer class
//It keeps a reference to the Concrete Subject objects
//It keeps the state that should stay consistent with the state of 
//the parent class
class ConcreteObserver extends Observer{
    constructor(id, subject, name){
        super();
        this.id = id;
        this.subject = subject; //a reference to the Concrete Subject object
        this.name = name;
        this.observerState = ""; // the state that should stay consistent with the state of
                                 //the parent class
    }

    //The interface for update object
    update() { 
        this.observerState = this.subject.subjectState; 
        console.log(`${this.name} new state is: ${this.observerState}`);
    }

   getSubject() {
        return this.subject;
    }

    setSubject(subject){
        this.subject = subject;
    }
};
//we will instantiate our concrete subject class that should be observed
var s = new ConcreteSubject();
//attaching the first concrete observer with an id of 1, 
//passing the concrete subject instance
//passing the name of the observer
s.attach(new ConcreteObserver(1, s, 'First observer'));
//attaching the second observer
s.attach(new ConcreteObserver(2, s, 'Second observer'));
//changing the subject state
s.setSubjectState("subject changed");
//notifying OBSERVERS (we have two observer at the moment) that the state was changed
s.notify();
/* OUTPUT OF THE NOTIFY FUNCTION
๐ŸŸข The Notification process starts...
First observer new state is: subject changed
Second observer new state is: subject changed
๐Ÿ”ด The Notification process ends...
*/
//detaching the observer with an id of 1
s.detach(1)
//changing the subject state
s.setSubjectState("removed one observer");
//notifying OBSERVER (because we detached our observer with an id of 1
//we are left with only one observer that should get notified about the
//change of the state
s.notify();
/* OUTPUT OF THE NOTIFY FUNCTION
๐ŸŸข The notification process starts...
Second observer new state is: removed one observer
๐Ÿ”ด The Notification process ends...
*/
Enter fullscreen mode Exit fullscreen mode

Please try executing this code, it is always better to look it in the text editor of your preference, and of course, play with it, try adding one more subject and as many observers as you want.

Here is the UML diagram for the visual learners.

Alt Text

๐ŸŒŽ REAL WORLD ANALOGY

๐Ÿ“ฐ NEWSPAPER / MAGAZINE 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 a new issue directly to your mailbox right after publication or even in advance. The publisher maintains a list of subscribers and knows which magazines they are interested in. Subscribers can leave the list at any time when they wish to stop the publisher from sending new magazine issues to them.

๐Ÿ“ˆ STOCK ANALOGY

The observer pattern also applies to the real world in terms of the stocks. For example, you can have an investor, a company for example Apple. Apple has stocks, investors invest their ๐Ÿ’ฐ into the Apple stocks, thus, they would certainly like to be notified when the stocks change so they can turn their strategy around.
In this case, a Stock is a Subject, Apple stock is a Concrete Subject, Investor is an Observer, and let's say Warren Buffet is a Concrete Observer.

โ“ WHEN TO USE THE OBSERVER PATTERN?

You could use the observer pattern when changes to the state of one object may require changing other objects, and the actual set of objects is unknown beforehand or changes dynamically.

Use the pattern when some objects in your app must observe others, but only for a limited time or in specific cases.

โš™ RxJS OBSERVABLE (ANGULAR)

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

The observer pattern is the pattern that RxJS observable is using.

Observable โ€” this is the thing that clients observe, it is sometimes called the subject.

Observer โ€” this is a class that wants to be notified when the subjectโ€™s state changes in an interesting way.

An Example of creating observables:

import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(observer) {
  var id = setInterval(() => {
    observer.next('hi')
  }, 1000);
});
Enter fullscreen mode Exit fullscreen mode

An Example of subscribing to an observable

observable.subscribe(x => console.log(x));
Enter fullscreen mode Exit fullscreen mode

When calling observable.subscribe with an Observer, the function subscribe in Observable.create(function subscribe(observer) {...}) is run for that given Observer. Each call to observable. Subscribe triggers its own independent setup for that given Observer.

โœ… PROS

  • Open/Closed Principle. You can introduce new subscriber classes without having to change the publisherโ€™s code (and vice versa if thereโ€™s a publisher interface).
  • You can establish relations between objects at runtime.

โŒ CONS

  • Subscribers are notified in random order.

๐Ÿ™ THANK YOU FOR READING!

Please leave the comment, tell me about you, about your work, comment your thoughts on the filter method, connect with me via Twitter or LinkedIn.

Let this year be your year, let this year be our year. Until the next typing...

Have a nice time!

References:
School notes...
medium
refactoring

โ˜• SUPPORT ME AND KEEP ME FOCUSED!
Buy Me a Coffee at ko-fi.com
๐Ÿ˜Š

Oldest comments (0)