Skip to content
Method约 1 分钟0 个小节更新于 2026/06/19在线编辑

访问者模式

访问者模式用于在不修改对象结构的情况下,给一组对象增加新的操作。

一句话理解:对象结构稳定,但操作经常增加,就把操作放到访问者里。

解决什么问题

假设有一组固定元素:

text
普通员工
经理
实习生

现在需要对这些元素做不同操作:

  • 计算薪资。
  • 导出报表。
  • 生成绩效。
  • 做权限检查。

如果每新增一种操作都去修改员工类,会违反开闭原则。访问者模式把操作抽离成访问者。

基本结构

text
Element.accept(Visitor)
Visitor.visit(ConcreteElement)

角色:

  • Visitor:访问者接口,定义访问不同元素的方法。
  • ConcreteVisitor:具体操作。
  • Element:元素接口,提供 accept
  • ConcreteElement:具体元素。

Java 示例

元素接口:

java
interface Employee {
    void accept(EmployeeVisitor visitor);
}

具体元素:

java
class Engineer implements Employee {
    private final int codeLines;

    Engineer(int codeLines) {
        this.codeLines = codeLines;
    }

    public int codeLines() {
        return codeLines;
    }

    public void accept(EmployeeVisitor visitor) {
        visitor.visit(this);
    }
}

class Manager implements Employee {
    private final int productCount;

    Manager(int productCount) {
        this.productCount = productCount;
    }

    public int productCount() {
        return productCount;
    }

    public void accept(EmployeeVisitor visitor) {
        visitor.visit(this);
    }
}

访问者接口:

java
interface EmployeeVisitor {
    void visit(Engineer engineer);

    void visit(Manager manager);
}

具体访问者:

java
class ReportVisitor implements EmployeeVisitor {
    public void visit(Engineer engineer) {
        System.out.println("engineer code lines: " + engineer.codeLines());
    }

    public void visit(Manager manager) {
        System.out.println("manager product count: " + manager.productCount());
    }
}

使用:

java
import java.util.Arrays;
import java.util.List;

List<Employee> employees = Arrays.asList(
        new Engineer(2000),
        new Manager(3)
);

EmployeeVisitor visitor = new ReportVisitor();
for (Employee employee : employees) {
    employee.accept(visitor);
}

使用场景

  • 对象结构稳定,操作经常增加。
  • 编译器 AST 遍历。
  • 报表导出。
  • 复杂对象结构统计。
  • 不同类型节点执行不同操作。

优点

  • 新增操作比较方便,只要新增访问者。
  • 把操作逻辑集中在访问者中。
  • 适合复杂对象结构的遍历和统计。

缺点

  • 新增元素类型很麻烦,需要修改所有访问者。
  • 破坏一定封装性,访问者常常需要读取元素内部数据。
  • 代码理解门槛较高。
  • 普通业务系统中使用频率不高。

双分派

访问者模式的核心是双分派:

text
第一次分派:employee.accept(visitor)
第二次分派:visitor.visit(this)

通过运行时元素类型,调用到对应的 visit 方法。

实战注意

如果元素类型经常变化,不适合访问者模式。如果操作经常变化,而元素结构长期稳定,访问者才有价值。

以工程实践沉淀知识,以文档复盘成长。