【Go-设计模式】访问者模式 详解

概念:
访问者模式(Visitor Pattern),封装一些作用于 某种数据结构 的 各元素的操作,它可以在 不改变数据结构 的前提下定义作用于这些元素的 新的操作
主要将 数据结构 与 数据操作 分离,解决 数据结构 和 操作耦合性 问题
工作原理:
在 被访问的类 里面加一个 对外提供接待访问者的接口

UML:

- Visitor:
是 抽象访问者,定义了 对每个 Element 访问的行为,它的参数就是 被访问的元素,它的 方法个数 理论上与 元素个数 是一样的
因此,访问者模式要求 元素的类型要稳定,如果经常 添加、移除 元素类,必然会导致 频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式 - ConcreteVisitor:
是一个 具体的访问者,它需要给出对 每一个元素类 访问时所产生的 具体行为 - Element:
定义一个 accept方法,接收一个访问者对象,意义是指 每一个元素 都要 可以被访问者访问 - ConcreteElement:
具体元素,实现了 accept 方法,接受访问者 - ObjectStructure:
定义上文 所提到的对象结构,对象结构是一个抽象表述,
它内部管理了元素集合,并且可以 迭代这些元素 提供 访问者访问入口
可以提供一个 高层的接口,用来 允许访问者访问元素 
示例:
抽象的访问者接口:
type Visitor interface {
	Visit(element Element)
}
具体的访问者类:
type ConcreteVisitor struct {
}
func (this ConcreteVisitor) VisitElement1(element Element) {
	var element1 = element.(*ConcreteElement1)
	fmt.Printf("visit the concrete visitor1,attribute is %s\n", element1.Attri)
}
func (this ConcreteVisitor) VisitElement2(element Element) {
	var element1 = element.(*ConcreteElement2)
	fmt.Printf("visit the concrete visitor1,attribute is %s\n", element1.Attri)
}
func NewConcreteVisitor() ConcreteVisitor {
	return ConcreteVisitor{}
}
抽象的元素功能接口:
type Element interface {
	Accept(Visitor)
}
具体的元素类:
具体的元素类1:
type ConcreteElement1 struct {
	Attri string
}
func (this *ConcreteElement1) Accept(visitor Visitor) {
	visitor.VisitElement1(this)
}
func NewConcreteElement1(desc string) ConcreteElement1 {
	return ConcreteElement1{
		Attri: desc,
	}
}
具体的元素类2:
type ConcreteElement2 struct {
	Attri string
}
func (this *ConcreteElement2) Accept(visitor Visitor) {
	visitor.VisitElement2(this)
}
func NewConcreteElement2(desc string) ConcreteElement2 {
	return ConcreteElement2{
		Attri: desc,
	}
}
对象结构类:
type ObjectStructure struct {
	Elements map[Element]struct{}
}
func (this *ObjectStructure) AddElement(ele Element) {
	this.Elements[ele] = struct{}{}
}
func (this ObjectStructure) RemoveElement(ele Element) {
	delete(this.Elements, ele)
}
func (this ObjectStructure) DoVisit(visitor Visitor) {
	for element := range this.Elements {
		element.Accept(visitor)
	}
}
func NewObjectStructure() ObjectStructure {
	return ObjectStructure{
		Elements: map[Element]struct{}{},
	}
}
测试:
package main
import "DemoProject/design/base23/visitor" // 根据自己的项目路径定制
func main() {
	// visitor
	objectStructure := visitor.NewObjectStructure()
	element1 := visitor.NewConcreteElement1("具体的元素实例1")
	objectStructure.AddElement(&element1)
	element2 := visitor.NewConcreteElement2("具体的元素实例2")
	objectStructure.AddElement(&element2)
	concreteVisitor := visitor.NewConcreteVisitor()
	objectStructure.DoVisit(concreteVisitor)
}
注意事项:
优点:
- 符合 单一职责原则
让程序具有 优秀的 扩展性、灵活性 - 使得 数据结构 和 作用于结构上的操作 解耦,使得 操作集合 可以 独立变化
 - 可以对 功能 进行 统一,
可以做 报表、UI、拦截器 与 过滤器,适用于 数据结构相对稳定的系统 - 如果需要 增加新的访问者,增加实现类 ConcreteVisitor 就可以 快速扩展
 - 如果一个系统有 比较稳定的数据结构,又有 经常变化的功能需求,那么访问者模式就是比较合适的
 
缺点:
- 
具体元素对访问者 公布细节
也就是说 访问者 关注了 其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难 - 
违背了 依赖倒转原则
访问者依赖的是 具体元素,而不是 抽象元素 
应用场景:
需要对一个 对象结构 中的对象进行很多 不同操作(这些操作 彼此没有关联),
同时需要 避免 让这些操作 "污染"这些对象的类,可以选用 访问者模式 解决

                
            
浙公网安备 33010602011771号