访问者模式是一种行为设计模式,它允许你在不修改已有类的情况下向这些类添加新的功能。
通过将算法与其作用的对象结构分离,可以在保持对象结构稳定的同时引入新的操作。
访问者(Visitor): 声明一个或多个访问方法,这些方法可以访问对象结构中不同类型的元素。
具体访问者(ConcreteVisitor): 实现每个由访问者声明的操作,每个操作对应于对象结构中的一个类。
元素(Element): 定义一个接受访问者的接口,通常包含一个Accept方法。
具体元素(ConcreteElement): 实现Accept方法,调用访问者的访问方法。
对象结构(ObjectStructure): 包含元素集合,并提供一个方法让访问者遍历所有元素。
开闭原则:在不修改现有类的情况下增加新功能。
单一职责原则:将相关操作集中在一个访问者类中,使类的职责更加单一。
扩展性:易于添加新的访问者,从而扩展系统功能。
编译器设计:语法树节点的不同操作(如类型检查、代码生成等)可以通过访问者模式实现。
图形应用:对复杂的图形结构进行操作,如绘图、碰撞检测等。
XML/HTML解析:对文档对象模型(DOM)进行不同的处理操作。
数据处理框架:对数据结构进行多种分析和处理操作。
访问者模式适用于对象结构相对稳定,但需要经常在此结构上定义新的操作的情形。
访问者模式的定义及使用流程可以分为以下几个步骤:
1 定义访问者接口:声明一个或多个访问方法,每个方法对应一个具体元素类。
2 定义元素接口:声明一个 Accept 方法,该方法接受一个访问者对象。
3 实现具体元素类:每个具体元素类实现 Accept 方法,并调用访问者的相应方法。
4 实现具体访问者类:实现访问者接口中声明的所有方法,每个方法定义了对相应元素的操作。
5 定义对象结构:包含一个元素集合,并提供一个 Accept 方法,用于让访问者遍历所有元素。
6 使用访问者:创建对象结构,添加元素,创建访问者,并调用对象结构的 Accept 方法,从而让访问者访问所有元素并执行相应操作。
package main
import (
"fmt"
"math"
)
// 1. Visitor 定义访问者接口
type Visitor interface {
// 访问圆形
VisitCircle(*Circle)
// 访问矩形
VisitRectangle(*Rectangle)
}
// 1.1 AreaCalculator 具体访问者:计算面积
// 1.1 AreaCalculator 实现了 Visitor 接口
type AreaCalculator struct {
Area float64
}
func (a *AreaCalculator) VisitCircle(c *Circle) {
a.Area += math.Pi * c.Radius * c.Radius
}
func (a *AreaCalculator) VisitRectangle(r *Rectangle) {
a.Area += r.Width * r.Height
}
// 2. Element 定义元素接口
type Element interface {
Accept(visitor Visitor)
}
// 2.1 Circle 具体元素:圆形
type Circle struct {
Radius float64
}
// 2.1.1
func (c *Circle) Accept(visitor Visitor) {
visitor.VisitCircle(c)
}
// 2.2 Rectangle 具体元素:矩形
type Rectangle struct {
Width float64
Height float64
}
// 2.2.1
func (r *Rectangle) Accept(visitor Visitor) {
visitor.VisitRectangle(r)
}
// 3. ObjectStructure 对象结构
type ObjectStructure struct {
Elements []Element
}
// 3.1 AddElement 添加元素
func (o *ObjectStructure) AddElement(element Element) {
o.Elements = append(o.Elements, element)
}
// 3.2 Accept 接受访问者
func (o *ObjectStructure) Accept(visitor Visitor) {
for _, element := range o.Elements {
element.Accept(visitor)
}
}
func main() {
// 创建对象结构
objectStructure := &ObjectStructure{}
// 添加元素
objectStructure.AddElement(&Circle{Radius: 5})
objectStructure.AddElement(&Rectangle{Width: 4, Height: 6})
// 创建访问者
areaCalculator := &AreaCalculator{}
// 访问对象结构中的元素
objectStructure.Accept(areaCalculator)
// 输出结果
fmt.Printf("Total Area: %.2f\n", areaCalculator.Area)
}