访问者模式

访问者模式概念

访问者模式是一种行为设计模式,它允许你在不修改已有类的情况下向这些类添加新的功能。

通过将算法与其作用的对象结构分离,可以在保持对象结构稳定的同时引入新的操作。

相关概念

访问者(Visitor): 声明一个或多个访问方法,这些方法可以访问对象结构中不同类型的元素。

具体访问者(ConcreteVisitor): 实现每个由访问者声明的操作,每个操作对应于对象结构中的一个类。

元素(Element): 定义一个接受访问者的接口,通常包含一个Accept方法。

具体元素(ConcreteElement): 实现Accept方法,调用访问者的访问方法。

对象结构(ObjectStructure): 包含元素集合,并提供一个方法让访问者遍历所有元素。

访问者模式作用

开闭原则:在不修改现有类的情况下增加新功能。

单一职责原则:将相关操作集中在一个访问者类中,使类的职责更加单一。

扩展性:易于添加新的访问者,从而扩展系统功能。

应用场景

编译器设计:语法树节点的不同操作(如类型检查、代码生成等)可以通过访问者模式实现。

图形应用:对复杂的图形结构进行操作,如绘图、碰撞检测等。

XML/HTML解析:对文档对象模型(DOM)进行不同的处理操作。

数据处理框架:对数据结构进行多种分析和处理操作。

访问者模式适用于对象结构相对稳定,但需要经常在此结构上定义新的操作的情形。

访问者模式定义、使用流程

访问者模式的定义及使用流程可以分为以下几个步骤:

1 定义访问者接口:声明一个或多个访问方法,每个方法对应一个具体元素类。
2 定义元素接口:声明一个 Accept 方法,该方法接受一个访问者对象。
3 实现具体元素类:每个具体元素类实现 Accept 方法,并调用访问者的相应方法。
4 实现具体访问者类:实现访问者接口中声明的所有方法,每个方法定义了对相应元素的操作。
5 定义对象结构:包含一个元素集合,并提供一个 Accept 方法,用于让访问者遍历所有元素。
6 使用访问者:创建对象结构,添加元素,创建访问者,并调用对象结构的 Accept 方法,从而让访问者访问所有元素并执行相应操作。

使用 GO 语言实现访问者模式

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)
}