Visitor Pattern(訪問者模式)

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.


示例代碼鏈接

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容