Skip to content

Commit 3ddfad1

Browse files
author
Badacadabra
committed
Add Observer (ES5 + ES6 + CoffeeScript + TypeScript)
1 parent 792c910 commit 3ddfad1

File tree

7 files changed

+324
-0
lines changed

7 files changed

+324
-0
lines changed
2.28 KB
Binary file not shown.
15 KB
Loading

doc/GoF/Behavioral/Observer/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Synopsis
2+
3+
In the savanna, there are predators like lions or crocodiles and there are preys like gazelles. So lions and crocodiles often attack gazelles.
4+
5+
# Problem
6+
7+
Lions and crocodiles do not attack at any moment. A lion will generally attack if a gazelle is a bit too far from the herd. A crocodile will generally attack if a gazelle is a bit too close to water, especially for drinking.
8+
9+
In programming terms, predators execute some action when a specific event occurs on the preys side. This implies the implementation of an event-handling mechanism in the code, which may be unclear if it is not properly done.
10+
11+
# Solution
12+
13+
The Observer design pattern helps a lot when we have to implement an event-driven system like this. Here this pattern is composed of:
14+
15+
* An abstract representation of preys which are observable objects (abstract class is preferred because each prey may have multiple predators)
16+
* An abstract representation of predators which are observers (abstract class or interface)
17+
* A concrete prey (Gazelle)
18+
* Concrete predators (Lion & Crocodile)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# ==============================
2+
# ABSTRACT OBSERVER
3+
# ==============================
4+
5+
class Predator
6+
constructor: ->
7+
throw new Error "You cannot instantiate an abstract class!" if @constructor is Predator
8+
9+
attack: ->
10+
throw new Error "You cannot call an abstract method!"
11+
12+
# ==============================
13+
# ABSTRACT OBSERVABLE
14+
# ==============================
15+
16+
class Prey
17+
constructor: ->
18+
throw new Error "You cannot instantiate an abstract class!" if @constructor is Prey
19+
@_predators = []
20+
21+
addPredator: (predator) ->
22+
@_predators.push predator
23+
24+
notifyPredators: ->
25+
situation = ""
26+
situation += predator.attack() for predator in @_predators
27+
situation
28+
29+
# ==============================
30+
# CONCRETE OBSERVERS
31+
# ==============================
32+
33+
class Lion extends Predator
34+
attack: ->
35+
"Lion attack!\n"
36+
37+
class Crocodile extends Predator
38+
attack: ->
39+
"Crocodile attack!\n"
40+
41+
# ==============================
42+
# CONCRETE OBSERVABLES
43+
# ==============================
44+
45+
class Gazelle extends Prey
46+
constructor: ->
47+
super
48+
49+
# ==============================
50+
# CLIENT CODE
51+
# ==============================
52+
53+
lion = new Lion
54+
crocodile = new Crocodile
55+
gazelle = new Gazelle
56+
57+
gazelle.addPredator lion
58+
gazelle.addPredator crocodile
59+
60+
console.log gazelle.notifyPredators()
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// ==============================
2+
// ABSTRACT OBSERVER
3+
// ==============================
4+
5+
interface Predator {
6+
attack(): string;
7+
}
8+
9+
// ==============================
10+
// ABSTRACT OBSERVABLE
11+
// ==============================
12+
13+
abstract class Prey {
14+
protected predators: Predator[] = [];
15+
16+
public addPredator(predator: Predator): void {
17+
this.predators.push(predator);
18+
}
19+
20+
public notifyPredators(): string {
21+
let situation: string = "";
22+
for (let predator of this.predators) {
23+
situation += predator.attack();
24+
}
25+
return situation;
26+
}
27+
}
28+
29+
// ==============================
30+
// CONCRETE OBSERVERS
31+
// ==============================
32+
33+
class Lion implements Predator {
34+
public attack(): string {
35+
return "Lion attack!\n";
36+
}
37+
}
38+
39+
class Crocodile implements Predator {
40+
public attack(): string {
41+
return "Crocodile attack!\n";
42+
}
43+
}
44+
45+
// ==============================
46+
// CONCRETE OBSERVABLES
47+
// ==============================
48+
49+
class Gazelle extends Prey {
50+
constructor() {
51+
super();
52+
}
53+
}
54+
55+
// ==============================
56+
// CLIENT CODE
57+
// ==============================
58+
59+
let lion: Predator = new Lion(),
60+
crocodile: Predator = new Crocodile(),
61+
gazelle: Prey = new Gazelle();
62+
63+
gazelle.addPredator(lion);
64+
gazelle.addPredator(crocodile);
65+
66+
console.log(gazelle.notifyPredators());
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
'use strict';
2+
3+
// ==============================
4+
// ABSTRACT OBSERVER
5+
// ==============================
6+
7+
var Predator = (function() {
8+
function Predator() {
9+
if (this.constructor === Predator) {
10+
throw new Error("You cannot instantiate an abstract class!");
11+
}
12+
}
13+
14+
Predator.prototype.attack = function () {
15+
throw new Error("You cannot call an abstract method!");
16+
};
17+
18+
return Predator;
19+
})();
20+
21+
// ==============================
22+
// ABSTRACT OBSERVABLE
23+
// ==============================
24+
25+
var Prey = (function () {
26+
function Prey() {
27+
if (this.constructor === Prey) {
28+
throw new Error("You cannot instantiate an abstract class!");
29+
}
30+
this._predators = [];
31+
}
32+
33+
Prey.prototype.addPredator = function (predator) {
34+
this._predators.push(predator);
35+
};
36+
37+
Prey.prototype.notifyPredators = function () {
38+
var situation = "";
39+
for (var i = 0, len = this._predators.length; i < len; i++) {
40+
situation += this._predators[i].attack();
41+
}
42+
return situation;
43+
};
44+
45+
return Prey;
46+
})();
47+
48+
// ==============================
49+
// CONCRETE OBSERVERS
50+
// ==============================
51+
52+
var Lion = (function () {
53+
function Lion() {}
54+
Lion.prototype = Object.create(Predator.prototype);
55+
Lion.prototype.constructor = Lion;
56+
57+
Lion.prototype.attack = function () {
58+
return "Lion attack!\n";
59+
};
60+
61+
return Lion;
62+
})();
63+
64+
var Crocodile = (function () {
65+
function Crocodile() {}
66+
Crocodile.prototype = Object.create(Predator.prototype);
67+
Crocodile.prototype.constructor = Crocodile;
68+
69+
Crocodile.prototype.attack = function () {
70+
return "Crocodile attack!\n";
71+
};
72+
73+
return Crocodile;
74+
})();
75+
76+
// ==============================
77+
// CONCRETE OBSERVABLES
78+
// ==============================
79+
80+
var Gazelle = (function () {
81+
function Gazelle() {
82+
Prey.call(this);
83+
}
84+
Gazelle.prototype = Object.create(Prey.prototype);
85+
Gazelle.prototype.constructor = Gazelle;
86+
87+
return Gazelle;
88+
})();
89+
90+
// ==============================
91+
// CLIENT CODE
92+
// ==============================
93+
94+
var lion = new Lion(),
95+
crocodile = new Crocodile(),
96+
gazelle = new Gazelle();
97+
98+
gazelle.addPredator(lion);
99+
gazelle.addPredator(crocodile);
100+
101+
console.log(gazelle.notifyPredators());
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// ==============================
2+
// ABSTRACT OBSERVER
3+
// ==============================
4+
5+
class Predator {
6+
constructor() {
7+
if (new.target !== undefined) {
8+
throw new Error("You cannot instantiate an abstract class!");
9+
}
10+
}
11+
12+
attack() {
13+
throw new Error("You cannot call an abstract method!");
14+
}
15+
}
16+
17+
// ==============================
18+
// ABSTRACT OBSERVABLE
19+
// ==============================
20+
21+
class Prey {
22+
constructor() {
23+
if (new.target !== undefined) {
24+
throw new Error("You cannot instantiate an abstract class!");
25+
}
26+
this._predators = [];
27+
}
28+
29+
addPredator(predator) {
30+
this._predators.push(predator);
31+
}
32+
33+
notifyPredators() {
34+
let situation = "";
35+
for (let predator of this._predators) {
36+
situation += predator.attack();
37+
}
38+
return situation;
39+
}
40+
}
41+
42+
// ==============================
43+
// CONCRETE OBSERVERS
44+
// ==============================
45+
46+
class Lion extends Predator {
47+
attack() {
48+
return "Lion attack!\n";
49+
}
50+
}
51+
52+
class Crocodile extends Predator {
53+
attack() {
54+
return "Crocodile attack!\n";
55+
}
56+
}
57+
58+
// ==============================
59+
// CONCRETE OBSERVABLES
60+
// ==============================
61+
62+
class Gazelle extends Prey {
63+
constructor() {
64+
super();
65+
}
66+
}
67+
68+
// ==============================
69+
// CLIENT CODE
70+
// ==============================
71+
72+
let lion = new Lion(),
73+
crocodile = new Crocodile(),
74+
gazelle = new Gazelle();
75+
76+
gazelle.addPredator(lion);
77+
gazelle.addPredator(crocodile);
78+
79+
console.log(gazelle.notifyPredators());

0 commit comments

Comments
 (0)