意图:
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
Gof给出的例子如下:
考虑编译器的语法分析树,其需要在抽象语法树上实施某些操作以进行“静态语义”分析,例如检查所有变量已经被定义了。同时,它也需要生成代码,因此要定义一些类型检查、代码优化、流程分析等工作。
然而这些操作对不同的节点对象需要不同的处理。如对赋值语句的节点的处理不同于对算术表达式节点的处理。因此有赋值语句的类,用于算术表达式的类等。
目标:
visitor模式旨在解决两个问题:
1) 改善对同一类操作分散到各个结点类的局面,使操作容易理解和维护。
2) 增加新的操作不需要重新编译这些类。只需定义操作就行,这个提供了很好的独立性
适用情形:
1) 你想对某个结构对象(包含一组不同的对象)实施一些依赖于某个具体类的操作
2) 避免让作用于不同对象的操作“污染”这些对象的类,可以将操作和对象独立开来
3) 访问对象结构相对比较稳定,需要改变的只是作用于不同对象的操作;如果访问对象的结构经常变化,那可能直接在对象中定义这些操作比较好。
UML描述:
时序图:
优点:
增加新的操作很容易,只需要增加具体的Visitor就行了;如果不用Visitor模式的话就需要修改各个具体Element对象
方便使用迭代器对各个具体Element对象进行操作,而各个具体对象不需要继承相同的父类
关键点:
使用Visitor模式,必须定义两个类层次:一个对应于接受操作的元素,另一个对应于定义对元素操作的访问者。对某个具体的对象进行accept操作时,accept操作将回调访问者,从而把对象指针传递给访问者,这样访问者能够操作具体的对象。
访问者模式是一种双重分派(double-dispatch)技术,意味着得到执行的操作决定于请求的种类和两个接收者的类型。双重分派使得访问者可以对每一个类元请求不同的操作
缺点:
增加新的ConcreteElement类很困难,因为新增类的同时需要在各个Visitor中增加访问该对象的方法。如果Visitor很多的话,工作量比较大。所以应用时需要考虑那部分相对稳定,适不适合使用Visitor模式。