Visitor
接口
class interface Visitor {
public visitor(Node node);
}
class interface Node {
public accpet(Visitor visitor);
}
作用
解耦了 数据结构 和 行为
示例
商店和客户
public class Merchant implements Node {
@Override
public void accept(Visitor v) {
v.visit(this);
}
public void orderGoodsA() {
System.out.println("order Goods A");
}
public void orderGoodsB() {
System.out.println("order Goods B");
}
}
public class CustomerA implements Visitor {
@Override
public void visit(Node n) {
if (n instanceof Merchant) {
((Merchant)n).orderGoodsA();
}
}
}
public class CustomerB implements Visitor {
@Override
public void visit(Node n) {
if (n instanceof Merchant) {
((Merchant)n).orderGoodsB();
}
}
}
调用和输出
@Test
public void visitorTest() throws Exception {
Merchant m = new Merchant();
CustomerA customerA = new CustomerA();
CustomerB customerB = new CustomerB();
m.accept(customerA);
m.accept(customerB);
}
> order Goods A
> order Goods B
访问文件目录树
调用和输出
@Test
public void visitorDirectoryTreeTest() throws Exception {
FileVisitor visitor = new FileVisitor() {
private int depth = 0;
@Override
public void visitorChildren(FileNode n) {
depth++;
File file = n.getFile();
StringBuilder sb = new StringBuilder();
for (int i = 1; i < depth; i++) {
sb.append("---");
}
sb.append(file.getName());
System.out.println(sb.toString());
if (file.isDirectory()) {
for (File f : file.listFiles()) {
FileNode node = new FileNode();
node.setFile(f);
node.accept(this);
}
}
depth--;
}
@Override
public void visit(Node n) {
if (n instanceof FileNode) {
this.visitorChildren((FileNode) n);
}
}
};
FileNode root = new FileNode();
root.setFile(new File("./test/res/parent"));
root.accept(visitor);
}
> parent
> |--child1
> |-----file1
> |--child2
> |-----file2
> |--file
实际的使用
主要还是行为和数据结构的分离, 针对一个数据结构, 通过统一的接口实现不同的操作或者行为.
如上面的示例, 对目录树,进行深度优先遍历, 同样可以使用同样的接口,进行广度优先遍历,实现对应的行为.
另外这种模式的使用,主要在编译器的语法分析器的实现中比较常见, 对于同一语法树, 实现不同的功能.
如clang的输出dot的CallGraph实现以及ANTLR4.