Observer Pattern

Posted by Dustin Boston in .

The Observer Pattern is a behavioral design pattern that establishes a one-to-many dependency between objects, enabling automatic updates to dependents when the subject’s state changes.


The Observer Pattern is a behavioral design pattern that defines a one-to-many
dependency between objects, ensuring that when one object changes state, all its dependents are notified and updated automatically. This pattern is particularly useful for implementing event-driven systems and maintaining consistency across related objects.

Source Code Listing

code.ts

import {LinkedList} from "../../algorithms/linked-list/code.ts";

type Observer = {
  update(subject: Subject): void;
};

class Subject {
  get counter() {
    return 0;
  }

  private readonly observers: LinkedList<Observer> = new LinkedList<Observer>();

  attach(observer: Observer): void {
    this.observers.append(observer);
  }

  detach(observer: Observer): void {
    this.observers.remove(observer);
  }

  notify(): void {
    const iterator = this.observers.createIterator();
    while (!iterator.isDone()) {
      const observer = iterator.currentItem();
      if (observer) {
        // Check if observer is not undefined
        observer.update(this);
      }

      iterator.next();
    }
  }
}

class ConcreteSubject extends Subject {
  // Concrete subject can have its own state or methods
  // that, when changed, trigger notifications
  someState = "";

  setState(newState: string): void {
    this.someState = newState;
    this.notify(); // Notify observers when state changes
  }
}

class ConcreteObserver implements Observer {
  update(subject: Subject): void {
    if (subject instanceof ConcreteSubject) {
      // Type guard
      console.log(`Updated. Subject's state: ${subject.someState}`);
    } else {
      console.log("Updated");
    }
  }
}

// List and Iterator implementations (from previous examples)
// ... (Include the List and Iterator implementations from the previous response here)

const example = {
  run(): void {
    const subject = new ConcreteSubject();
    const observer = new ConcreteObserver();

    subject.attach(observer);
    subject.setState("New State!"); // Example of state change and notification

    const observer2 = new ConcreteObserver();
    subject.attach(observer2);
    subject.setState("Another State!"); // Example with multiple observers

    subject.detach(observer); // Detach an observer
    subject.setState("Yet Another State!"); // Observer should not be notified
  },
};

Example.run();