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.