访问者模式是一种行为设计模式,它允许在不改变数据结构的情况下,定义新的操作(访问者)并应用于数据结构中的元素。在这种模式下,我们将数据结构和操作之间的耦合分离,使得新增操作时不需要修改元素的类
访问者模式的核心思想是将操作封装在访问者对象中,而不是分散在被访问的对象中。被访问的对象通过接受访问者的访问,将自身作为参数传递给访问者,从而实现对自身操作的解耦和扩展
它会导致代码的可读性、可维护性变差,所以,访问者模式在实际的软件开发中很 少被用到,在没有特别必要的情况下,建议不要使用访问者模式。
逻辑结构

代码实现
代码路径:https://github.com/XBoom/DesignPatterns/tree/main/20_Visitor
-
首先,定义一个访问者接口
Visitor
,表示访问不同的元素1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// Visitor 访问者接口
type Visitor interface {
VisitConcreteElementA(element *ConcreteElementA)
VisitConcreteElementB(element *ConcreteElementB)
}
// ConcreteVisitor 具体访问者
type ConcreteVisitor struct{}
func (v *ConcreteVisitor) VisitConcreteElementA(element *ConcreteElementA) {
fmt.Println("访问者正在访问具体元素 A")
}
func (v *ConcreteVisitor) VisitConcreteElementB(element *ConcreteElementB) {
fmt.Println("访问者正在访问具体元素 B")
} -
然后,定义多个具体元素结构体,它们实现了接受访问者访问的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// Element 元素接口
type Element interface {
Accept(visitor Visitor)
}
// ConcreteElementA 具体元素 A
type ConcreteElementA struct{}
func (e *ConcreteElementA) Accept(visitor Visitor) {
visitor.VisitConcreteElementA(e)
}
// ConcreteElementB 具体元素 B
type ConcreteElementB struct{}
func (e *ConcreteElementB) Accept(visitor Visitor) {
visitor.VisitConcreteElementB(e)
} -
接着,定义一个具体的访问者结构体,它实现了访问者接口中定义的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14// ObjectStructure 对象结构
type ObjectStructure struct {
elements []Element
}
func (o *ObjectStructure) Attach(element Element) {
o.elements = append(o.elements, element)
}
func (o *ObjectStructure) Accept(visitor Visitor) {
for _, element := range o.elements {
element.Accept(visitor)
}
}
运行
1 | objectStructure := &ObjectStructure{} |
结果
1 | 访问者正在访问具体元素 A |
适用场景
- 当一个对象的结构较为稳定,但对该对象的操作却经常变化时,使用访问者模式可以将操作的变化封装在访问者对象中,而不影响元素对象的稳定性。
- 当需要对一个对象结构中的多个元素进行操作,并且这些操作具有一定的关联性时,可以使用访问者模式将这些操作封装在一个访问者中,提高代码的复用性和可维护性。
- 当对象结构中的元素类数量较少且固定时,使用访问者模式可以简化代码结构,将元素的操作集中在访问者中,减少代码的分散性。
总结
- 开闭原则。 可以引入在不同类对象上执行的新行为, 且无需对这些类做出修改。
- 单一职责原则。 可将同一行为的不同版本移到同一个类中。
- 访问者对象可以在与各种对象交互时收集一些有用的信息。 当你想要遍历一些复杂的对象结构 (例如对象树), 并在结构中的每个对象上应用访问者时, 这些信息可能会有所帮助