一、概述
这个设计模式可以封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于其内部各个元素的新操作。
二、应用场景
当你有个类,里面的包含各种类型的元素,这个类结构比较稳定,不会经常增删不同类型的元素。而需要经常给这些元素添加新的操作的时候,考虑使用此设计模式。
三、UML类图
Visitor包含5个角色
- ObjectStructure
这个角色就是我们的对象结构,对应上面的大忽悠科技有限公司:BigHuYouCompany
。此对象结构包含各种元素,而且要求元素稳定且可以迭代访问这些元素。
- Visitor
大名鼎鼎的访问者,它是一个接口。里面定义了与元素对应的visite(Element)
方法,一般是有几个元素就相应的有几个visite方法。
- ConcreteVisitor
visitor的实现类
- Element
是一个接口,代表在ObjectStructure里面的元素。里面定义了一个accept(Visiotr)
的方法,通过此方法元素可以将自己交给Visitor访问。
- ConcreteElement
element 的实现类
四、双分派(dispatch)
访问者模式存在一个叫"伪动态双分派”的技术,这个还是比较难懂的,访问者模式之所以是最复杂的设计模式与其有很大的关系。
什么叫分派?根据对象的类型而对方法进行的选择,就是分派(Dispatch)。
发生在编译时的分派叫静态分派,例如重载(overload),发生在运行时的分派叫动态分派,例如重写(overwrite)。
单分派与多分派
- 单分派
依据单个宗量进行方法的选择就叫单分派,Java 动态分派只根据方法的接收者一个宗量进行分配,所以其是单分派
- 多分派
依据多个宗量进行方法的选择就叫多分派,Java 静态分派要根据方法的接收者与参数这两个宗量进行分配,所以其是多分派
好了,理论的只是罗列出来了,那具体到访问者模式是个什么情况呢?
先看在BigHuYouCompany
类里的分派代码:slave.accept(visitor);
中accept方法的分派是由slave的运行时类型决定的。若slave是Programer
就执行Programer
的accept方法。若slave是Tester
那么就执行Tester
的accept方法。
public void startProject(CorporateSlaveVisitor visitor){
for (CorporateSlave slave : employee) {
slave.accept(visitor);
}
}
通过此步骤就完成了一次动态单分派。
再看一下具体的Element
里的分派代码:visitor.visit(this);
中visit方法的分派是由参数 this
的运行时类型决定的。若this是Programer
就执行Visitor
中的visit(Programer)
方法。若slave是Tester
那么就执行Visitor
的visit(Tester)
方法。
@Override
public void accept(CorporateSlaveVisitor visitor) {
visitor.visit(this);
}
通过这一步又完成了一次动态单分派。
两次动态单分派结合起来就完成了一次伪动态双分派,为什么叫伪动态装派呢?因为在Java中动态分派是单分派的,而此处是通过两次动态单分派达到了双分派的效果,所以说是伪的!
五、优缺点
优点
- 使得给结构稳定的对象增加新算法变得容易,提搞了代码的可维护性,可扩展性。
缺点
- 太复杂,特别是伪动态双分派,不仔细理解很难想清楚。
六、访问者模式要点总结
- 准确识别出Visitor实用的场景,如果一个对象结构不稳定决不可使用,不然在增删元素时改动将非常巨大。
- 对象结构中的元素要可以迭代访问
- Visitor里一般存在与元素个数相同的visit方法。
- 元素通过
accept
方法通过this
将自己传递给了Visitor。
注:
1. visitor设计模式类似于升级版的策略模式,它们都属于行为型设计模式,用于解耦对象与其具体行为之间的关系。
2. visitor设计模式 和策略模式的区别:
策略模式:是通过定义一系列算法类,将每个算法封装在独立的策略类中,使得它们可以互相替换。在使用策略模式时,客户端会选择一个具体的策略对象来执行特定的算法。策略模式提供了一种灵活的方式来动态改变对象的行为。
Visitor设计模式:主要用于处理对象结构中不同类型的元素,并根据元素的具体类型执行不同的操作。它将操作封装在一个访问者(Visitor)对象中,通过在元素类中定义一个accept方法,将自身作为参数传递给访问者,在访问者中通过重载visit方法来处理不同的元素类型。
虽然Visitor设计模式和策略模式类似,都可以实现在运行时动态改变对象的行为,但二者的应用场景和实现方式有所不同。Visitor设计模式更适合处理对象结构中的元素,并对不同类型的元素执行不同的操作,而策略模式更适合在算法族中选择合适的算法进行使用。