十八、visitor 访问者模式
视频: https://www.bilibili.com/video/BV1dp4y1J7qi/?spm_id_from=333.337.search-card.all.click&vd_source=5dfe92471f5072eaffbf480e25acd82d
https://refactoringguru.cn/design-patterns/visitor
visitor 模式强调的是 “访问” 的动作
如果 visitor 希望访问 interviewee, 可以让 interviewee 提供 accept() 方法, 该方法内部调用的还是 visitor.visit() 方法
好处是: interviewee 可以方便扩展增加更多 visitor 的访问
18.1 fruit_visitor 水果访问者
水果 visitor
├── fruit.go
├── readme.md
├── visitor.go
└── visitor_test.go
18.1.1 visitor_test.go
package _81fruit_visitor
import (
"fmt"
"testing"
)
/*
=== RUN TestVisitFruit
apple 开始被访问了
visitor1 访问 apple
apple 结束被访问了
apple 开始被访问了
visitor2 访问 apple
apple 结束被访问了
orange 开始被访问了
visitor1 访问 orange
orange 结束被访问了
orange 开始被访问了
visitor2 访问 orange
orange 结束被访问了
--- PASS: TestVisitFruit (0.00s)
PASS
*/
func TestVisitFruit(t *testing.T) {
fs := []fruit{&apple{}, &orange{}}
vs := []visitor{&visitor1{}, &visitor2{}}
for _, f := range fs {
for _, v := range vs {
f.accept(v)
}
fmt.Println()
}
}
18.1.2 visitor.go
package _81fruit_visitor
import "fmt"
type visitor interface {
visit(fruit)
}
type visitor1 struct {
}
func (v *visitor1) visit(f fruit) {
fmt.Printf("visitor1 访问 %v\n", f.name())
}
type visitor2 struct {
}
func (v *visitor2) visit(f fruit) {
fmt.Printf("visitor2 访问 %v\n", f.name())
}
18.1.3 fruit.go
package _81fruit_visitor
import "fmt"
type fruit interface {
accept(visitor)
name() string
}
type apple struct{}
func (f *apple) accept(v visitor) {
fmt.Printf("%v 开始被访问了\n", f.name())
v.visit(f)
fmt.Printf("%v 结束被访问了\n", f.name())
}
func (f *apple) name() string {
return "apple"
}
type orange struct{}
func (f *orange) accept(v visitor) {
fmt.Printf("%v 开始被访问了\n", f.name())
v.visit(f)
fmt.Printf("%v 结束被访问了\n", f.name())
}
func (f *orange) name() string {
return "orange"
}