访问者模式

  • 定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

访问者模式

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
interface Component {
// 接收
accept(visitor: Visitor): void;
}
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';
}
}

interface Visitor {
visitConcreteComponentA(element: ConcreteComponentA): void;

visitConcreteComponentB(element: ConcreteComponentB): void;
}
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`);
}
}

//使用
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);
  • 缺点:
    • 元素的改变需要更新所有的访问者,无法解耦