全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-11 7 分钟 ✍️ juanwangdev

Java访问者模式

访问者模式将操作从对象结构分离,使操作可独立变化。

模式定义

意图:将操作从对象结构分离,不改变结构前提下定义新操作。

适用场景

  • 对象结构稳定,操作经常变化
  • 需要对不同类型元素执行不同操作
  • 数据结构与操作解耦

模式结构

Visitor接口

Java
public interface Visitor {
    void visit(ElementA element);
    void visit(ElementB element);
    void visit(ElementC element);
}

Element接口

Java
public interface Element {
    void accept(Visitor visitor);
}

具体Element

Java
public class ElementA implements Element {
    private String name;

    public ElementA(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);  // 双分派
    }
}

public class ElementB implements Element {
    private int value;

    public ElementB(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

具体Visitor

Java
public class PrintVisitor implements Visitor {
    @Override
    public void visit(ElementA element) {
        System.out.println("ElementA: " + element.getName());
    }

    @Override
    public void visit(ElementB element) {
        System.out.println("ElementB: " + element.getValue());
    }
}

public class SumVisitor implements Visitor {
    private int sum = 0;

    @Override
    public void visit(ElementA element) {
        // ElementA不参与求和
    }

    @Override
    public void visit(ElementB element) {
        sum += element.getValue();
    }

    public int getSum() {
        return sum;
    }
}

对象结构

Java
public class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

使用示例

Java
ObjectStructure structure = new ObjectStructure();
structure.addElement(new ElementA("A1"));
structure.addElement(new ElementB(10));
structure.addElement(new ElementA("A2"));
structure.addElement(new ElementB(20));

// 打印操作
structure.accept(new PrintVisitor());
// ElementA: A1
// ElementB: 10
// ElementA: A2
// ElementB: 20

// 求和操作
SumVisitor sumVisitor = new SumVisitor();
structure.accept(sumVisitor);
System.out.println("总和: " + sumVisitor.getSum());  // 30

双分派机制

访问者模式使用双分派:

Java
// 第一次分派:element.accept(visitor) → 根据Element类型选择方法
// 第二次分派:visitor.visit(this) → 根据Visitor类型选择方法

Element element = new ElementA();
Visitor visitor = new PrintVisitor();

element.accept(visitor);
// ElementA.accept() → visitor.visit(this)
// PrintVisitor.visit(ElementA) → 双分派确定具体方法

实际应用示例

文件系统访问

Java
public interface FileVisitor {
    void visit(File file);
    void visit(Directory directory);
}

public interface FileNode {
    void accept(FileVisitor visitor);
}

public class File implements FileNode {
    private String name;
    private int size;

    @Override
    public void accept(FileVisitor visitor) {
        visitor.visit(this);
    }

    public String getName() { return name; }
    public int getSize() { return size; }
}

public class Directory implements FileNode {
    private String name;
    private List<FileNode> children = new ArrayList<>();

    @Override
    public void accept(FileVisitor visitor) {
        visitor.visit(this);
        for (FileNode child : children) {
            child.accept(visitor);
        }
    }

    public void add(FileNode node) { children.add(node); }
    public String getName() { return name; }
}

// 计算文件大小
public class SizeVisitor implements FileVisitor {
    private int totalSize = 0;

    @Override
    public void visit(File file) {
        totalSize += file.getSize();
    }

    @Override
    public void visit(Directory directory) {
        // 目录本身不计大小
    }

    public int getTotalSize() { return totalSize; }
}

// 搜索文件
public class SearchVisitor implements FileVisitor {
    private String keyword;
    private List<File> results = new ArrayList<>();

    public SearchVisitor(String keyword) {
        this.keyword = keyword;
    }

    @Override
    public void visit(File file) {
        if (file.getName().contains(keyword)) {
            results.add(file);
        }
    }

    @Override
    public void visit(Directory directory) {
        if (directory.getName().contains(keyword)) {
            System.out.println("找到目录: " + directory.getName());
        }
    }

    public List<File> getResults() { return results; }
}

访问者模式优点

  1. 新增操作只需新增Visitor
  2. 操作集中管理
  3. 对象结构与操作解耦

访问者模式缺点

  1. 新增Element类型需修改所有Visitor
  2. Element需暴露内部状态给Visitor
  3. 违反依赖倒置原则(Element依赖Visitor)

适用场景

  1. 对象结构稳定,操作多变
  2. 复杂数据结构处理
  3. 编译器语法树处理
  4. 文件系统遍历

注意事项

Element结构应稳定,否则修改代价大

Visitor需为每种Element提供visit方法

双分派使具体方法由Element和Visitor共同决定

可结合组合模式处理树形结构

要点总结

  1. 访问者模式将操作从对象结构分离
  2. Visitor定义visit方法,Element定义accept方法
  3. 双分派确定具体执行方法
  4. 新增操作容易,新增Element困难
  5. 适用于数据结构稳定、操作变化的场景

📝 发现内容有误?点击此处直接编辑

← 上一篇 Java解释器模式
下一篇 → Java责任链模式
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库