访问者模式将遍历与处理逻辑分离,通过双重分派实现类型精准匹配:元素类提供accept()调用visitor.visit(this),访问者接口按子类重载visit()方法,客户端以document.accept(new visitor())触发递归访问。

Java 中访问者模式操作复杂对象结构,核心在于把“遍历逻辑”和“处理逻辑”分开:对象结构只负责组织和暴露元素,访问者负责定义对每种元素做什么。它不靠修改原有类,而是靠双重分派机制,在运行时精准匹配元素类型与访问行为。
明确对象结构的组成方式
复杂对象结构通常是一组有继承关系的元素(如 Document → Paragraph / Image / Table),它们共同实现一个 Element 接口,并提供 accept(Visitor v) 方法。结构本身(比如 Document 或 CompositeNode)用集合(List<element></element>)持有子元素,提供 acceptAll(Visitor) 或类似遍历入口。
- 元素类必须稳定——新增元素类型成本高,但新增操作(访问者)非常轻量
- 每个具体元素的
accept()方法只做一件事:v.visit(this),把“自己”传给访问者 - 结构容器不关心具体操作,只负责按序调用各元素的
accept()
定义访问者接口并实现具体行为
访问者接口按元素类型声明多个 visit() 方法,方法签名区分具体子类(如 visit(Image img)、visit(Paragraph p))。Java 依赖重载 + 运行时类型推导完成第二次分派。
- 一个
HtmlExportVisitor实现所有visitXxx(),分别生成对应 HTML 片段 - 一个
WordCountVisitor在visit(Paragraph)中统计字数,在visit(Image)中跳过或记为“1图” - 方法名一致、参数类型不同——这是 Java 支持该模式的关键语法基础
在客户端触发完整访问流程
客户端不直接调用元素方法,而是构造访问者实例,再把它“推入”结构顶层:
-
document.accept(new HtmlExportVisitor())—— 顶层元素接收访问者 -
document内部遍历子元素,逐个调用child.accept(visitor) - 每个子元素(如
Image)执行visitor.visit(this),JVM 根据this的实际类型选中visit(Image) - 整个过程递归向下,无需 if-else 类型判断,也不侵入元素类内部
注意几个关键约束
该模式高效的前提是结构相对封闭:
- 元素类型不宜频繁增删——加一个新
Video类,所有访问者都要补一个visit(Video)方法 - 元素需向访问者适度开放数据(如
getText()、getSrc()),否则访问者无法工作 - 避免在
accept()中做业务逻辑,它只是调度入口;真正逻辑全在访问者方法里
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











