响应式个人网站模板下载软文素材网
Golang学习笔记_44——命令模式
 Golang学习笔记_45——备忘录模式
 Golang学习笔记_46——状态模式
文章目录
- 一、核心概念
 - 1. 定义
 - 2. 解决的问题
 - 3. 核心角色
 - 4. 类图
 
- 二、特点分析
 - 三、适用场景
 - 1. 编译器实现
 - 2. 财务系统
 - 3. UI组件系统
 
- 四、Go语言实现示例
 - 完整实现代码
 - 执行结果
 
- 五、高级应用
 - 1. 异步访问者
 - 2. 动态派发优化
 
- 六、与其他模式对比
 - 七、实现建议
 - 八、典型应用
 
一、核心概念
1. 定义
访问者模式是一种行为型设计模式,允许在不修改已有对象结构的前提下定义新的操作。其核心特点包括:
 • 操作解耦:将数据操作与数据结构分离
 • 双重分发:通过两次方法调用实现动态绑定
 • 扩展开放:新增操作无需修改现有类
2. 解决的问题
• 操作污染:频繁添加新操作导致类不断膨胀
 • 聚合困难:相关操作分散在不同类中
 • 类型检查:避免大量instanceof类型判断
3. 核心角色
| 角色 | 作用 | 
|---|---|
| Visitor | 声明访问操作的接口(visit方法) | 
| ConcreteVisitor | 实现具体访问逻辑 | 
| Element | 定义接受访问者的接口(accept方法) | 
| ConcreteElement | 实现accept方法的具体元素 | 
| ObjectStructure | 包含元素集合的容器 | 
4. 类图

@startuml
interface Visitor {+ visitElementA(e: ElementA)+ visitElementB(e: ElementB)
}class TaxVisitor {+ visitElementA()+ visitElementB()
}interface Element {+ accept(v: Visitor)
}class ElementA {+ accept(v: Visitor)+ operationA()
}class ElementB {+ accept(v: Visitor)+ operationB()
}Visitor <|.. TaxVisitor
Element <|.. ElementA
Element <|.. ElementB
ElementA ..> Visitor
ElementB ..> Visitornote right of ElementA::accept调用visitor.visitElementA(this)实现双重分派机制
end note
@enduml
 
二、特点分析
优点
- 扩展性强:新增访问者不影响现有系统
 - 职责清晰:相关操作集中管理
 - 复合操作:支持跨元素的复杂操作
 
缺点
- 破坏封装:需暴露元素内部细节
 - 维护困难:元素接口变更影响所有访问者
 - 适用局限:适合稳定元素结构的系统
 
三、适用场景
1. 编译器实现
type ASTVisitor interface {VisitVariableDecl(n *VariableDecl)VisitFunctionCall(n *FunctionCall)
}type TypeChecker struct{}func (t *TypeChecker) VisitVariableDecl(n *VariableDecl) {fmt.Printf("校验变量 %s 的类型\n", n.Name)
}
 
2. 财务系统
type FinancialVisitor interface {VisitInvoice(i *Invoice)VisitPayment(p *Payment)
}type TaxCalculator struct{}func (t *TaxCalculator) VisitInvoice(i *Invoice) {fmt.Printf("计算发票税款:%.2f\n", i.Amount*0.1)
}
 
3. UI组件系统
type UIVisitor interface {VisitButton(b *Button)VisitPanel(p *Panel)
}class Renderer struct{}func (r *Renderer) VisitButton(b *Button) {fmt.Printf("渲染按钮:%s\n", b.Label)
}
 
四、Go语言实现示例

完整实现代码
package visitor_demoimport "fmt"// Visitor 接口
type ComputerPartVisitor interface {VisitMouse(m *Mouse)VisitKeyboard(k *Keyboard)
}// Concrete Visitor
type DisplayVisitor struct{}func (d *DisplayVisitor) VisitMouse(m *Mouse) {fmt.Println("显示鼠标信息:", m.GetSpec())
}func (d *DisplayVisitor) VisitKeyboard(k *Keyboard) {fmt.Println("显示键盘信息:", k.GetLayout())
}// Element 接口
type ComputerPart interface {Accept(visitor ComputerPartVisitor)
}// Concrete Elements
type Mouse struct {dpi int
}func (m *Mouse) Accept(visitor ComputerPartVisitor) {visitor.VisitMouse(m)
}func (m *Mouse) GetSpec() string {return fmt.Sprintf("%d DPI", m.dpi)
}type Keyboard struct {layout string
}func (k *Keyboard) Accept(visitor ComputerPartVisitor) {visitor.VisitKeyboard(k)
}func (k *Keyboard) GetLayout() string {return k.layout
}// Object Structure
type Computer struct {parts []ComputerPart
}func (c *Computer) AddPart(p ComputerPart) {c.parts = append(c.parts, p)
}func (c *Computer) Accept(visitor ComputerPartVisitor) {for _, p := range c.parts {p.Accept(visitor)}
}// 客户端使用示例
func ExampleUsage() {computer := &Computer{parts: []ComputerPart{&Mouse{dpi: 1600},&Keyboard{layout: "QWERTY"},},}visitor := &DisplayVisitor{}computer.Accept(visitor)
}
 
执行结果
=== RUN   TestExampleUsage
显示鼠标信息: 1600 DPI
显示键盘信息: QWERTY
--- PASS: TestExampleUsage (0.00s)
PASS
 
五、高级应用
1. 异步访问者
type AsyncVisitor interface {VisitForDB(n Node) <-chan errorVisitForAPI(n Node) <-chan error
}func BatchVisit(nodes []Node, v AsyncVisitor) []error {// 实现并发访问处理
}
 
2. 动态派发优化
type DynamicVisitor struct {handlers map[reflect.Type]func(interface{})
}func (dv *DynamicVisitor) Register(t reflect.Type, fn func(interface{})) {dv.handlers[t] = fn
}
 
六、与其他模式对比
| 模式 | 核心区别 | 典型应用场景 | 
|---|---|---|
| 策略模式 | 单算法选择 vs 多元素操作 | 支付方式选择 | 
| 装饰器模式 | 增强功能 vs 添加操作 | IO流处理 | 
| 组合模式 | 树形结构 vs 元素遍历 | 文件系统管理 | 
七、实现建议
- 访问者接口设计
 
type Visitor interface {VisitTypeA(*TypeA)VisitTypeB(*TypeB)DefaultVisit(interface{})
}
 
- 元素继承处理
 
type BaseElement struct{}func (b *BaseElement) Accept(v Visitor) {v.DefaultVisit(b)
}
 
- 循环引用处理
 
type Element struct {visitor Visitor `json:"-"` // 避免序列化循环
}
 
- 访问者状态管理
 
type StatefulVisitor struct {buffer strings.Builder
}
 
八、典型应用
- 编译器构建:语法树检查/优化
 - 数据分析:异构数据集合统计
 - 游戏引擎:场景实体遍历更新
 - 文档处理:多格式导出系统
 
在Go语言中实现建议:
- 使用接口组合代替继承
 - 通过类型断言实现泛型访问者
 - 结合通道实现并发访问
 - 使用sync.Pool优化高频访问对象
 
