一、基本概念
访问者模式属于设计模式中的【行为型设计模式】,它将行为和具体的数据结构进行了分离。在23种设计模式中,它相对比较复杂,难理解。
二、实现
我们先不探究使用访问者模式的原因,简单来看看访问者模式的实现。
其实访问者模式就像它名字所形容的,可以比喻为多个客人对一个包含多个家庭成员的家庭进行访问,到访的客人会一次和家庭的每个成员进行寒暄,所以它的三个组成要素就是:客人、家庭、以及家庭成员。
以下是行为模式Golang的一个实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| package main
import "fmt"
//家庭成员接口 type Member interface { //定义一个与访问者发生寒暄的方法 Accept(Visitor) }
//家里的小女儿 type daughter struct{}
//与访问者互相寒暄 func (d *daughter) Accept(v Visitor) { v.Visit(d) }
//家里的小儿子 type son struct{}
//与访问者互相寒暄 func (s *son) Accept(v Visitor) { v.Visit(s) }
//访问者接口 type Visitor interface { //和家庭成员寒暄时要进行的对应操作定义在这里 Visit(Member) }
//爸爸的同学1 type Classmate1 struct{}
//这是一个玩具厂老板,给孩子送玩具 func (c *Classmate1) Visit(member Member) { switch member.(type) { case *son: fmt.Println("送给一个擎天柱") case *daughter: fmt.Println("送给一个洋娃娃") } }
//爸爸的同学2 type Classmate2 struct{}
//这是一个程序员,给孩子送编程书 func (c *Classmate2) Visit(member Member) { switch member.(type) { case *daughter: fmt.Println("送一本Java大全") case *son: fmt.Println("送一本前端宝典") } }
//家庭类 type Family struct { members []Member }
//添加家庭成员 func (f *Family) Add(m Member) { f.members = append(f.members, m) }
//聚会开始 func (f *Family) Party(v Visitor) { for _, m := range f.members { m.Accept(v) } }
func main() { //首先定义家庭成员 family := Family{} family.Add(&son{}) family.Add(&daughter{})
//根据不同的访问者,和家庭成员之间产生不同的行为 //玩具老板给两个孩子送玩具 v1 := &Classmate1{} family.Party(v1) //程序员给孩子送编程书籍 v2 := &Classmate2{} family.Party(v2) }
|
这段代码其实是一个小故事,两个访客分别来家里拜访,一个人是玩具厂老板,他看到家里的小女儿,会送一套洋娃娃,看到小儿子,会送一个擎天柱,一个人是程序员,他看到小女儿,会送本前端宝典,看到家里的小儿子,会送本Java大全。
三、为什么需要访问者模式
从上面的故事,我们可以看出,家庭成员具体发生了什么行为是由来拜访的访客所决定,故事里所有行为都是定义在了访客身上(送书、送玩具),而我们的家庭成员本身与行为是解耦开的。
在业务中我们经常会遇到一种情况,同族类不断膨胀的业务操作,例如:我们我们要处理很多文件类型的文件,他们都要执行读取、写入的操作。
对于这种需求,我们通常的做法就是定义一个txt类、pdf类等文件类,他们都实现read和write方法。但是当需要再额外增加几个新的文件操作,例如:文件压缩、文件水印等时,我们会发现了几个问题:
- 添加一个新功能,需要给所有的文件类都添加这个操作,违背了开闭原则
- 随着业务操作和数据类的不断耦合,类违背了单一职责原则
而访问模式通过将行为定义到visitor中,并通过family为媒介,实现member成员类与行为的解耦,行为的增加只需要定义一个新的访问者即可。