本文首發於我的博客html
本文代碼爲java代碼java
在訪問者模式(Visitor Pattern)中,咱們使用了一個訪問者類,它改變了元素類的執行算法。經過這種方式,元素的執行算法能夠隨着訪問者改變而改變。這種類型的設計模式屬於行爲型模式。根據模式,元素對象已接受訪問者對象,這樣訪問者對象就能夠處理元素對象上的操做。git
假設咱們寫了一個平衡二叉樹,那麼對應的確定有對應的確定有添加元素,刪除元素,中序遍歷,後序遍歷...等等。咱們就以中序遍歷二叉樹爲例,先看不用訪問者模式會有什麼問題。github
建立Node
節點類,有左子樹,右子樹,父節點算法
public static class Node<E> {
Integer element;
Node<Integer> left;
Node<Integer> right;
Node<Integer> parent;
public Node(Integer element, Node<Integer> parent) {
this.element = element;
this.parent = parent;
}
}
複製代碼
建立BinarySearchTree
類,有size,根節點root
, 添加,刪除,遍歷等等設計模式
public class BinarySearchTree<Integer> {
private int size;
public Node<Integer> root;
public void add(Integer element) {
//添加的代碼就不寫了
}
public void remove(Integer element) {
//刪除的代碼就不寫了
}
... 其餘接口
// 中序遍歷
private void inorder(Node<Integer> node) {
if (node == null ) return;
// 遍歷左子樹
inorder(node.left);
// 打印
System.out.println(node.element);
// 遍歷右子樹
inorder(node.right);
}
}
複製代碼
上面的代碼是否也是能夠用的,調用inorder
遍歷以後,這個二叉樹能夠按照中序遍歷的方式打印出來,彷佛沒什麼問題。可是仔細想一想,其實存在問題的。由於這個咱們寫死了是打印出元素,假設咱們真正使用的時候,不是想直接打印呢?而是想每一個元素的值加上2 而後再打印呢?又或者每一個元素的值加上10,並且不想打印呢?bash
你可能會說,那簡單啊,直接改啊,例如每一個元素的值加上2 而後再打印數據結構
public class BinarySearchTree<Integer> {
//... 其餘接口
// 中序遍歷
private void inorder(Node<Integer> node) {
if (node == null ) return;
// 遍歷左子樹
inorder(node.left);
// 打印
System.out.println(node.element + 2);
// 遍歷右子樹
inorder(node.right);
}
}
複製代碼
看起來也沒問題,既然是加上2再打印那就直接加上2再打印咯。可是有以下兩個問題ui
也就是說,有沒有一種不修改遍歷的具體實現,就能知足不一樣場景下的遍歷呢?答案是有的,就是訪問者模式
public class BinarySearchTree<Integer> {
private int size;
public Node<Integer> root;
public void add(Integer element) {
//添加的代碼就不寫了
}
public void remove(Integer element) {
//刪除的代碼就不寫了
}
... 其餘接口
// 中序遍歷
public void inorder(Visitor<Integer> visitor) {
if (visitor == null) return;
inorder(root, visitor);
}
private void inorder(Node<Integer> node, Visitor<Integer> visitor) {
if (node == null ) return;
//遍歷左子樹
inorder(node.left, visitor);
// 元素給visitor,具體的邏輯由外界的visitor處理
visitor.visit(node.element);
//遍歷右子樹
inorder(node.right, visitor);
}
}
複製代碼
這樣修改以後,使用的時候
每一個節點的值加上2再打印
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
bst.preorder(new Visitor<Integer>() {
public boolean visit(Integer element) {
System.out.print(element + 2);
}
});
複製代碼
每一個節點的值加上10再打印
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
bst.preorder(new Visitor<Integer>() {
public boolean visit(Integer element) {
System.out.print(element + 10);
}
});
複製代碼
這樣的話,不管使用者如何更改需求,不一樣的場景下,都不用修改二叉樹內部的遍歷代碼,均可以知足。