Skip to content

Commit e73f3aa

Browse files
author
Badacadabra
committed
Add Visitor (ES5 + ES6 + CoffeeScript + TypeScript)
1 parent 9bd3888 commit e73f3aa

File tree

7 files changed

+289
-0
lines changed

7 files changed

+289
-0
lines changed

doc/GoF/Behavioral/Visitor/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Synopsis
2+
3+
I love history and I would like to visit more old monuments. But these are treasures of the past that must be protected to remain undamaged.
4+
5+
# Problem
6+
7+
If any individual can enter a historical monument and degrade it, we can say that the original structure is definitely lost. To preserve that structure, people should not be allowed to enter historical monuments without permission and supervision.
8+
9+
Applied to JavaScript, we could say this is very easy to modify directly the structure of an object and we may be tempted to do so. *But this is not what we want...
10+
11+
# Solution
12+
13+
The Visitor design pattern is a way to preserve an object structure. Operations on this object structure are still possible but they are kept separate to some extent, so they do not modify its essence.
14+
15+
To implement the Visitor design pattern, we need:
16+
17+
* An abstract representation of a visitor (abstract class or interface)
18+
* An abstract representation of a historical monument (abstract class or interface)
19+
* A concrete visitor (Tourist)
20+
* Concrete historical monuments (Castle & Abbey)
2.16 KB
Binary file not shown.
16.6 KB
Loading
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# ==============================
2+
# ABSTRACT MONUMENT
3+
# ==============================
4+
5+
class HistoricalMonument
6+
constructor: ->
7+
throw new Error "You cannot instantiate an abstract class!" if @constructor is HistoricalMonument
8+
9+
accept: (visitor) ->
10+
throw new Error "You cannot instantiate an abstract class!"
11+
12+
# ==============================
13+
# ABSTRACT VISITOR
14+
# ==============================
15+
16+
class Visitor
17+
constructor: ->
18+
throw new Error "You cannot instantiate an abstract class!" if @constructor is Visitor
19+
20+
visit: (monument) ->
21+
throw new Error "You cannot call an abstract method!"
22+
23+
# ==============================
24+
# CONCRETE MONUMENTS
25+
# ==============================
26+
27+
class Castle extends HistoricalMonument
28+
accept: (visitor) ->
29+
visitor.visit(@)
30+
31+
class Abbey extends HistoricalMonument
32+
accept: (visitor) ->
33+
visitor.visit(@)
34+
35+
# ==============================
36+
# CONCRETE VISITOR
37+
# ==============================
38+
39+
class Tourist extends Visitor
40+
visit: (monument) ->
41+
"Visiting #{monument.constructor.name}"
42+
43+
# ==============================
44+
# CLIENT CODE
45+
# ==============================
46+
47+
castle = new Castle
48+
abbey = new Abbey
49+
tourist = new Tourist
50+
51+
console.log castle.accept tourist
52+
console.log abbey.accept tourist
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// ==============================
2+
// ABSTRACT MONUMENT
3+
// ==============================
4+
5+
interface HistoricalMonument {
6+
accept(visitor: Visitor): string;
7+
}
8+
9+
// ==============================
10+
// ABSTRACT VISITOR
11+
// ==============================
12+
13+
interface Visitor {
14+
visit(monument: HistoricalMonument): string;
15+
}
16+
17+
// ==============================
18+
// CONCRETE MONUMENTS
19+
// ==============================
20+
21+
class Castle implements HistoricalMonument {
22+
public accept(visitor: Visitor): string {
23+
return visitor.visit(this);
24+
}
25+
}
26+
27+
class Abbey implements HistoricalMonument {
28+
public accept(visitor: Visitor): string {
29+
return visitor.visit(this);
30+
}
31+
}
32+
33+
// ==============================
34+
// CONCRETE VISITOR
35+
// ==============================
36+
37+
// Necessary declaration in TypeScript to access a class name (see the "visit" method)
38+
interface Function {
39+
name: string;
40+
}
41+
42+
class Tourist implements Visitor {
43+
public visit(monument: HistoricalMonument): string {
44+
return `Visiting ${monument.constructor.name}`;
45+
}
46+
}
47+
48+
// ==============================
49+
// CLIENT CODE
50+
// ==============================
51+
52+
let castle: HistoricalMonument = new Castle(),
53+
abbey: HistoricalMonument = new Abbey(),
54+
tourist: Visitor = new Tourist();
55+
56+
console.log(castle.accept(tourist));
57+
console.log(abbey.accept(tourist));
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
'use strict';
2+
3+
// ==============================
4+
// ABSTRACT MONUMENT
5+
// ==============================
6+
7+
var HistoricalMonument = (function() {
8+
function HistoricalMonument() {
9+
if (this.constructor === HistoricalMonument) {
10+
throw new Error("You cannot instantiate an abstract class!");
11+
}
12+
}
13+
14+
HistoricalMonument.prototype.accept = function (visitor) {
15+
throw new Error("You cannot instantiate an abstract class!");
16+
};
17+
18+
return HistoricalMonument;
19+
})();
20+
21+
// ==============================
22+
// ABSTRACT VISITOR
23+
// ==============================
24+
25+
var Visitor = (function() {
26+
function Visitor() {
27+
if (this.constructor === Visitor) {
28+
throw new Error("You cannot instantiate an abstract class!");
29+
}
30+
}
31+
32+
Visitor.prototype.visit = function (monument) {
33+
throw new Error("You cannot call an abstract method!");
34+
};
35+
36+
return Visitor;
37+
})();
38+
39+
// ==============================
40+
// CONCRETE MONUMENTS
41+
// ==============================
42+
43+
var Castle = (function () {
44+
function Castle() {}
45+
Castle.prototype = Object.create(HistoricalMonument.prototype);
46+
Castle.prototype.constructor = Castle;
47+
48+
Castle.prototype.accept = function (visitor) {
49+
return visitor.visit(this);
50+
};
51+
52+
return Castle;
53+
})();
54+
55+
var Abbey = (function () {
56+
function Abbey() {}
57+
Abbey.prototype = Object.create(HistoricalMonument.prototype);
58+
Abbey.prototype.constructor = Abbey;
59+
60+
Abbey.prototype.accept = function (visitor) {
61+
return visitor.visit(this);
62+
};
63+
64+
return Abbey;
65+
})();
66+
67+
// ==============================
68+
// CONCRETE VISITOR
69+
// ==============================
70+
71+
var Tourist = (function () {
72+
function Tourist() {}
73+
Tourist.prototype = Object.create(Visitor.prototype);
74+
Tourist.prototype.constructor = Tourist;
75+
76+
Tourist.prototype.visit = function (monument) {
77+
return "Visiting " + monument.constructor.name;
78+
};
79+
80+
return Tourist;
81+
})();
82+
83+
// ==============================
84+
// CLIENT CODE
85+
// ==============================
86+
87+
var castle = new Castle(),
88+
abbey = new Abbey(),
89+
tourist = new Tourist();
90+
91+
console.log(castle.accept(tourist));
92+
console.log(abbey.accept(tourist));
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// ==============================
2+
// ABSTRACT MONUMENT
3+
// ==============================
4+
5+
class HistoricalMonument {
6+
constructor() {
7+
if (new.target !== undefined) {
8+
throw new Error("You cannot instantiate an abstract class!");
9+
}
10+
}
11+
12+
accept(visitor) {
13+
throw new Error("You cannot instantiate an abstract class!");
14+
}
15+
}
16+
17+
// ==============================
18+
// ABSTRACT VISITOR
19+
// ==============================
20+
21+
class Visitor {
22+
constructor() {
23+
if (new.target !== undefined) {
24+
throw new Error("You cannot instantiate an abstract class!");
25+
}
26+
}
27+
28+
visit(monument) {
29+
throw new Error("You cannot call an abstract method!");
30+
}
31+
}
32+
33+
// ==============================
34+
// CONCRETE MONUMENTS
35+
// ==============================
36+
37+
class Castle extends HistoricalMonument {
38+
accept(visitor) {
39+
return visitor.visit(this);
40+
}
41+
}
42+
43+
class Abbey extends HistoricalMonument {
44+
accept(visitor) {
45+
return visitor.visit(this);
46+
}
47+
}
48+
49+
// ==============================
50+
// CONCRETE VISITOR
51+
// ==============================
52+
53+
class Tourist extends Visitor {
54+
visit(monument) {
55+
return `Visiting ${monument.constructor.name}`;
56+
}
57+
}
58+
59+
// ==============================
60+
// CLIENT CODE
61+
// ==============================
62+
63+
let castle = new Castle(),
64+
abbey = new Abbey(),
65+
tourist = new Tourist();
66+
67+
console.log(castle.accept(tourist));
68+
console.log(abbey.accept(tourist));

0 commit comments

Comments
 (0)