访问者模式(Visitor Pattern)是一种将数据结构与数据操作分离的设计模式,指封装一些作用于某种数据结构中的各元素的操作,可以在不改变数据结构的前提下定义作用于这些元素的新的操作,属于行为型设计模式。
场景
- 需要遍历很多不同的实现的对象,并且遍历的过程中对不同类型的对象有不同的处理,替代使用instanceof的做法
- 需要数据结构与数据操作分离
- 被访问者类型稳定
伪动态双分派,accept一次visit一次
- 重载 静态绑定 编译期决定 参数的类型
- 覆写 动态绑定 运行时决定 调用者的类型
java静态多分派动态单分派

- 抽象访问者(IVisitor):接口或抽象类,该类定义了一个visit()方法用于访问每一个具体的元素,其参数就是具体的元素对象。从理论上来说,IVisitor的方法个数与元素种类个数是相等的。如果元素种类个数经常变动,则导致IVisitor的方法也要进行变动,此时,该情形并不适用于访问者模式。
- 具体访问者(ConcreteVisitor):实现对具体元素的操作。
- 抽象元素(IElement):接口或抽象类,定义了一个接受访问者访问的方法accept(),表示所有元素类型都支持被访问者访问。
- 具体元素(ConcreteElement):具体元素类型,提供接受访问者的具体实现。通常的实现都为visitor.visit(this)。
- 结构对象(ObjectStructure):该类内部维护了元素集合,并提供方法接受访问者对该集合所有元素进行操作。
public interface IElement {void accept(IVisitor visitor);}public interface IVisitor {void visit(ElementA element);void visit(ElementB element);}public class ElementA implements IElement {@Overridepublic void accept(IVisitor visitor) {visitor.visit(this);}public void operationA(){}}public class ElementB implements IElement {@Overridepublic void accept(IVisitor visitor) {//visitor第二次动态分派,this静态分派visitor.visit(this);}public void operationB(){}}public class ConcreteVisitorA implements IVisitor {@Overridepublic void visit(ElementA element) {element.operationA();}@Overridepublic void visit(ElementB element) {element.operationB();}}public class ConcreteVisitorB implements IVisitor {@Overridepublic void visit(ElementA element) {}@Overridepublic void visit(ElementB element) {}}public class Client {public static void main(String[] args){IVisitor visitorA = new ConcreteVisitorA();IVisitor visitorB = new ConcreteVisitorB();List<IElement> list = new ArrayList<>();for(IElement element : list){//第一次动态分派element.accept(visitorA);element.accept(visitorB);}}}
优点
- 解耦数据结构与数据操作,通过扩展类型的访问者实现对元素集的不同操作
- 增加访问者简单,符合开闭原则
缺点
- 访问者依赖具体元素而不是抽象元素,具体元素的修改会影响每个访问者,同时访问者需要关注具体元素的实现细节
- 违法依赖倒置原则
- 增加或者修改被访问者困难
