Design Patterns: Observer - Part 1
this pattern is a behavioral pattern, taken from the classic book of the gang of four. bellow is my implementation in typescript with a concrete example.
abstract class Observer {
abstract update(): void;
}
abstract class Subject {
abstract subscribe(o: Observer): void;
abstract unsubscribe(o: Observer): void;
abstract notifyAll(): void;
}
Once we have these interfaces, we can go ahead and define the concrete classes:
class Singer extends Subject {
private _state: Number;
private _subscribers: Observer[];
constructor(state = 0) {
super();
this._state = state;
this._subscribers = [];
console.log("a new singer created, with state: " + this.state);
}
subscribe(o: Observer): void {
this._subscribers.push(o);
console.log("current subscribers: " + this._subscribers.toString());
}
unsubscribe(o: Observer): void {
const i = this._subscribers.indexOf(o);
this._subscribers.splice(i, 1);
console.log("current subscribers: " + this._subscribers.toString());
}
notifyAll(): void {
for(let o of this._subscribers) {
o.update();
}
console.log("All subscribers have been notified!");
}
get state() {
return this._state;
}
set state(val: Number) {
this._state = val;
this.notifyAll();
}
}
class Groopie extends Observer {
private _state: Number = 0;
private _singer: Singer = null as any;
update(): void {
this._state = this._singer.state;
console.log("state updated: current value: " + this._state);
}
get state(): Number {
return this._state;
}
constructor(singer: Singer) {
super();
this._singer = singer;
this._singer.subscribe(this);
this.update();
}
}
const slash = new Singer(0);
const jane = new Groopie(slash);
console.log(jane.state);
slash.state = 2;
const john = new Groopie(slash);
console.log(jane.state);
console.log(john.state);
slash.unsubscribe(jane);
slash.state = 8;
console.log(jane.state);
console.log(john.state);
slash.subscribe(jane);
slash.state = 16;
console.log(jane.state);
console.log(john.state);
abstract class Observer {
abstract update(): void;
}
abstract class Subject {
abstract subscribe(o: Observer): void;
abstract unsubscribe(o: Observer): void;
abstract notifyAll(): vo...
Play with this code in TypeScript Playground
Variations:
In the next post we will discuss and implement the following scenario: What if the observers can subscribe to multiple subjects?
This arises several issues about redunant notifications, we will see two approaches to this problem.
stay tuned!