TypeScript Observer Pattern Example

In this article, we will learn how to use and implement the Observer Pattern in TypeScript with an example.
Observer 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.

TypeScript Observer Pattern Example

The below diagram shows the generic structure of the Observer Pattern:
Let's refer to the above structure to create an example to demonstrates the usage of the Observer Pattern.
Let's create observer.ts file and add the following code to it:
export class Subject {
    private observers: Observer[] = [];

    public register(observer: Observer): void {
        console.log(observer, "is pushed!");
        this.observers.push(observer);
    }

    public unregister(observer: Observer): void {
        var n: number = this.observers.indexOf(observer);
        console.log(observer, "is removed");
        this.observers.splice(n, 1);
    }

    public notify(): void {
        console.log("notify all the observers", this.observers);
        var i: number
            , max: number;

        for (i = 0, max = this.observers.length; i < max; i += 1) {
            this.observers[i].notify();
        }
    }
}

export class ConcreteSubject extends Subject {
    private subjectState: number;

    get SubjectState(): number {
        return this.subjectState;
    }

    set SubjectState(subjectState: number) {
        this.subjectState = subjectState;
    }
}

export class Observer {
    public notify(): void {
        throw new Error("Abstract Method!");
    }
}

export class ConcreteObserver extends Observer {
    private name: string;
    private state: number;
    private subject: ConcreteSubject;

    constructor (subject: ConcreteSubject, name: string) {
        super();
        console.log("ConcreteObserver", name, "is created!");
        this.subject = subject;
        this.name = name;
    }

    public notify(): void {
        console.log("ConcreteObserver's notify method");
        this.state = this.subject.SubjectState;
        console.log(this.name, this.state);
    }

    get Subject(): ConcreteSubject {
        return this.subject;
    }

    set Subject(subject: ConcreteSubject) {
        this.subject = subject;
    }
}

Usage

Let's create demo.ts file and add the following code to it:
import { ConcreteObserver, ConcreteSubject } from "./observer";

export function show() : void {
 var sub: ConcreteSubject = new ConcreteSubject();

 sub.register(new ConcreteObserver(sub, "user1"));
 sub.register(new ConcreteObserver(sub, "user2"));
 sub.register(new ConcreteObserver(sub, "user3"));

 sub.SubjectState = 125;
 sub.notify();

}
show();
Run:
  • Compile the above code using the TypeScript compiler.
  • Above code is compiled to plan JavaScript code
  • Run Javascript code using node
design_patterns_in_typescript\observer> tsc --target ES5 .\demo.ts
design_patterns_in_typescript\observer> node .\demo.js
ConcreteObserver user1 is created!
ConcreteObserver {
  subject: ConcreteSubject { observers: [] },
  name: 'user1'
} is pushed!
ConcreteObserver user2 is created!
ConcreteObserver {
  subject: ConcreteSubject { observers: [ [ConcreteObserver] ] },
  name: 'user2'
} is pushed!
ConcreteObserver user3 is created!
ConcreteObserver {
  subject: ConcreteSubject {
    observers: [ [ConcreteObserver], [ConcreteObserver] ]
  },
  name: 'user3'
} is pushed!
notify all the observers [
  ConcreteObserver {
    subject: ConcreteSubject { observers: [Circular], subjectState: 125 },
    name: 'user1'
  },
  ConcreteObserver {
    subject: ConcreteSubject { observers: [Circular], subjectState: 125 },
    name: 'user2'
  },
  ConcreteObserver {
    subject: ConcreteSubject { observers: [Circular], subjectState: 125 },
    name: 'user3'
  }
]
ConcreteObserver's notify method
user1 125
ConcreteObserver's notify method
user2 125
ConcreteObserver's notify method
user3 125

When to Use Observer Pattern 

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.

All TypeScript Design Patterns

1. Creational Design Patterns

Creational patterns provide various object creation mechanisms, which increase flexibility and reuse of existing code.
  1. TypeScript Singleton Pattern Example
  2. TypeScript Factory Design Pattern with Example
  3. TypeScript Abstract Factory Pattern Example
  4. TypeScript Builder Pattern Example
  5. TypeScript Prototype Pattern Example

2. Structural Design Patterns

Structural patterns explain how to assemble objects and classes into larger structures while keeping these structures flexible and efficient.
  1. TypeScript Bridge Pattern Example
  2. TypeScript Adapter Pattern Example
  3. TypeScript Decorator Pattern Example
  4. TypeScript Composite Pattern Example
  5. TypeScript Flyweight Design Pattern Example
  6. TypeScript Facade Pattern Example
  7. TypeScript Proxy Pattern Example

3. Behavioral Design Patterns

Behavioral design patterns are concerned with algorithms and the assignment of responsibilities between objects.

  1. TypeScript Command Pattern Example
  2. TypeScript Chain of Responsibility Pattern Example
  3. TypeScript Visitor Pattern Example
  4. TypeScript Template Method Pattern Example
  5. TypeScript Strategy Pattern Example
  6. TypeScript State Pattern Example
  7. TypeScript Observer Pattern Example
  8. TypeScript Memento Pattern Example
  9. TypeScript Mediator Pattern Example
  10. TypeScript Iterator Pattern Example
  11. TypeScript Interpreter Design Pattern Example