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; }
}
访问者模式优点
- 新增操作只需新增Visitor
- 操作集中管理
- 对象结构与操作解耦
访问者模式缺点
- 新增Element类型需修改所有Visitor
- Element需暴露内部状态给Visitor
- 违反依赖倒置原则(Element依赖Visitor)
适用场景
- 对象结构稳定,操作多变
- 复杂数据结构处理
- 编译器语法树处理
- 文件系统遍历
注意事项
Element结构应稳定,否则修改代价大
Visitor需为每种Element提供visit方法
双分派使具体方法由Element和Visitor共同决定
可结合组合模式处理树形结构
要点总结
- 访问者模式将操作从对象结构分离
- Visitor定义visit方法,Element定义accept方法
- 双分派确定具体执行方法
- 新增操作容易,新增Element困难
- 适用于数据结构稳定、操作变化的场景
📝 发现内容有误?点击此处直接编辑