Loading...
Loading...
By continuing to use the platform, you accept the terms of the Privacy Policy and the use of cookies.
Observer is behavioral design pattern that allows objects to subscribe to events occurring in another object and automatically receive notifications about changes in its state. Object sending messages is called subject, and objects subscribing to its notifications — observers.
Pattern Idea:
"Observer" simplifies coordination and maintaining consistency between several objects, allowing one object (Subject) to notify others (Observers) about its changes without hard binding to their implementation.
When one object must inform others about its changes, but shouldn't know details of their implementation (low coupling principle).
When there are several dependent objects (observers) that must react to changes in one object (subject).
When number of observers isn't fixed at compile time, and should change "on the fly".
Subject Interface
Describes methods for subscribing (attach) and unsubscribing (detach) observers, as well as for notifying (notify).
Observer Interface
Contains update() method that's called by subject.
Concrete Subject
Stores state that observers can track, and implements subscribe/unsubscribe methods. When state changes calls notify().
Concrete Observer
Reacts to notifications by getting needed data from subject.
// 1. Observer interface
interface Observer {
update(subject: Subject): void;
}
// 2. Subject interface
interface Subject {
attach(observer: Observer): void;
detach(observer: Observer): void;
notify(): void;
}
// 3. Concrete subject
class ConcreteSubject implements Subject {
private observers: Observer[] = [];
private state: number = 0;
public attach(observer: Observer): void {
this.observers.push(observer);
}
public detach(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
public notify(): void {
for (const observer of this.observers) {
observer.update(this);
}
}
// Example state change
public setState(value: number) {
this.state = value;
console.log(`Subject: state changed to ${this.state}`);
this.notify();
}
public getState(): number {
return this.state;
}
}
// 4. Concrete observers
class ConcreteObserverA implements Observer {
public update(subject: Subject): void {
if (subject instanceof ConcreteSubject && subject.getState() < 5) {
console.log("ConcreteObserverA reacts, as state < 5");
}
}
}
class ConcreteObserverB implements Observer {
public update(subject: Subject): void {
if (subject instanceof ConcreteSubject && subject.getState() >= 5) {
console.log("ConcreteObserverB reacts, as state >= 5");
}
}
}
// Usage example
function clientCode() {
const subject = new ConcreteSubject();
const observerA = new ConcreteObserverA();
const observerB = new ConcreteObserverB();
subject.attach(observerA);
subject.attach(observerB);
// Change state
subject.setState(3);
subject.setState(7);
subject.detach(observerA);
subject.setState(2); // Now only observerB tracks
}
clientCode();
Important:
Observer pattern can be potentially dangerous with large number of subscribers or complex dependencies. Carefully track what events are sent and where, to avoid turning project into "spaghetti" code.
Observer pattern simplifies implementing reactive applications and reduces coupling between components. It's widely used in frontend (e.g., in Flux/Redux architecture, where subscribers react to store state changes). However, be careful with potential complexity growth with large number of subscribers and intersecting events.
Read more about Observer here.