-
抽象访问者 Visitor,根据需要访问的元素,通过重载定义各自的访问方法,对调用方element是透明的:
- visit(ConcreteElement1)
- visit(ConcreteElement2)
... - visit(ConcreteElementN)
-
ConcreteVisitor
- visit 定义了访问方法的逻辑,组织调用被访问元素Element的业务逻辑doSomething方法
-
抽象元素 Element
- doSomething 定义业务逻辑
- accept(Visitor) 那些抽象访问者可以访问自己
-
ConcreteElement
- 实现doSomething
- 实现accept方法,一般调用visitor对应的访问方法visit
结论
- 本质上就是element.accept开始驱动 -> visitor.visit -> element.doSomething,多了一层访问者。
- 针对访问对象的不同,执行不同的展现操作。
优点
- 符合单一职责原则,visitor负责展现逻辑,element负责业务逻辑。
- 展现的扩展性,只需在visitor里增加应对新element子类的visit方法即可。
缺点
- visitor依赖了element的实现。
- 修改element的业务逻辑同时,visitor也要做相应改动,修改困难。
双分派
- 这里涉及到一个重要的Java概念:静态绑定和动态绑定
ParentElement xxx = new ChildElement();
ParentVisitor zzz = new ChildVisitor();
// act的参数传的是zzz,zzz的表面类型是Parent,如果有2个重载方法,act(parent) 和 act(child),调用的是前者,哪怕zzz的实际类型是child,这是编译期决定的静态绑定。
// xxx的实际类型是child,所以调用的act是child的act,而不是parent的act,这是运行期决定的动态绑定。
xxx.act(zzz)
引入到访问者模式
public class ChildElement implements Element {
// 注意,虽然形参类型是parent,但实际调用visit方法是动态绑定,所以调用的还是childVisitor的visit方法
public void accept(ParentVisitor visitor) {
// 而且element调用accept方法本身就是动态绑定,所以访问者模式可以做到2个都是动态绑定。
visitor.visit(this);
}
}
网友评论