My App

访问者模式

Visitor — 在不修改类的前提下,为其添加新的操作

一句话理解

操作从数据结构中抽离出来,放到独立的"访问者"中。数据结构不变,想加新操作就加新访问者。

解决什么问题

  • 数据结构稳定,但需要频繁添加新的操作
  • 不想每次加操作都去修改数据类

怎么写

以"文件系统分析"为例:文件结构固定,但分析方式多种多样(统计大小、列出名称等)。

// 访问者接口
public interface FileVisitor {
    void visit(TextFile file);
    void visit(ImageFile file);
}

// 元素接口
public interface FileElement {
    void accept(FileVisitor visitor);
}

// 具体元素
public class TextFile implements FileElement {
    private final String name;
    private final int lines;
    public TextFile(String name, int lines) { this.name = name; this.lines = lines; }
    public String getName() { return name; }
    public int getLines() { return lines; }
    public void accept(FileVisitor visitor) { visitor.visit(this); }
}

public class ImageFile implements FileElement {
    private final String name;
    private final long sizeKB;
    public ImageFile(String name, long sizeKB) { this.name = name; this.sizeKB = sizeKB; }
    public String getName() { return name; }
    public long getSizeKB() { return sizeKB; }
    public void accept(FileVisitor visitor) { visitor.visit(this); }
}

// 具体访问者:统计信息
public class SummaryVisitor implements FileVisitor {
    private int totalLines = 0;
    private long totalSize = 0;

    public void visit(TextFile f) { totalLines += f.getLines(); }
    public void visit(ImageFile f) { totalSize += f.getSizeKB(); }

    public void report() {
        System.out.println("文本总行数: " + totalLines);
        System.out.println("图片总大小: " + totalSize + "KB");
    }
}
List<FileElement> files = List.of(
    new TextFile("readme.md", 100),
    new TextFile("code.java", 500),
    new ImageFile("logo.png", 200)
);

SummaryVisitor visitor = new SummaryVisitor();
files.forEach(f -> f.accept(visitor));
visitor.report();
// 文本总行数: 600
// 图片总大小: 200KB

使用场景

  • 编译器中的 AST(抽象语法树)遍历
  • 文档导出(同一份文档 → HTML/PDF/Markdown)
  • 代码分析工具(统计行数、复杂度、依赖关系)
  • Java 的 FileVisitor(NIO Files.walkFileTree)

On this page