-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVisitor.ts
130 lines (114 loc) · 3.84 KB
/
Visitor.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* The Component interface declares an `accept` method that should take the base
* visitor interface as an argument.
*/
interface Component {
accept(visitor: Visitor): void;
}
/**
* Each Concrete Component must implement the `accept` method in such a way that
* it calls the visitor's method corresponding to the component's class.
*/
class ConcreteComponentA implements Component {
/**
* Note that we're calling `visitConcreteComponentA`, which matches the
* current class name. This way we let the visitor know the class of the
* component it works with.
*/
public accept(visitor: Visitor): void {
visitor.visitConcreteComponentA(this);
}
/**
* Concrete Components may have special methods that don't exist in their
* base class or interface. The Visitor is still able to use these methods
* since it's aware of the component's concrete class.
*/
public exclusiveMethodOfConcreteComponentA(): string {
return 'A';
}
}
class ConcreteComponentB implements Component {
/**
* Same here: visitConcreteComponentB => ConcreteComponentB
*/
public accept(visitor: Visitor): void {
visitor.visitConcreteComponentB(this);
}
public specialMethodOfConcreteComponentB(): string {
return 'B';
}
}
/**
* The Visitor Interface declares a set of visiting methods that correspond to
* component classes. The signature of a visiting method allows the visitor to
* identify the exact class of the component that it's dealing with.
*/
interface Visitor {
visitConcreteComponentA(element: ConcreteComponentA): void;
visitConcreteComponentB(element: ConcreteComponentB): void;
}
/**
* Concrete Visitors implement several versions of the same algorithm, which can
* work with all concrete component classes.
*
* You can experience the biggest benefit of the Visitor pattern when using it
* with a complex object structure, such as a Composite tree. In this case, it
* might be helpful to store some intermediate state of the algorithm while
* executing visitor's methods over various objects of the structure.
*/
class ConcreteVisitor1 implements Visitor {
public visitConcreteComponentA(element: ConcreteComponentA): void {
console.log(
`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor1`
);
}
public visitConcreteComponentB(element: ConcreteComponentB): void {
console.log(
`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor1`
);
}
}
class ConcreteVisitor2 implements Visitor {
public visitConcreteComponentA(element: ConcreteComponentA): void {
console.log(
`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor2`
);
}
public visitConcreteComponentB(element: ConcreteComponentB): void {
console.log(
`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor2`
);
}
}
/**
* The client code can run visitor operations over any set of elements without
* figuring out their concrete classes. The accept operation directs a call to
* the appropriate operation in the visitor object.
*/
function clientCode(components: Component[], visitor: Visitor) {
// ...
for (const component of components) {
component.accept(visitor);
}
// ...
}
const components = [new ConcreteComponentA(), new ConcreteComponentB()];
console.log(
'The client code works with all visitors via the base Visitor interface:'
);
const visitor1 = new ConcreteVisitor1();
clientCode(components, visitor1);
console.log('');
console.log(
'It allows the same client code to work with different types of visitors:'
);
const visitor2 = new ConcreteVisitor2();
clientCode(components, visitor2);
/* OUTPUT
The client code works with all visitors via the base Visitor interface:
A + ConcreteVisitor1
B + ConcreteVisitor1
It allows the same client code to work with different types of visitors:
A + ConcreteVisitor2
B + ConcreteVisitor2
*/