語法樹可以理解成是一種數據結構,假如某些語句已經被解析成一棵語法樹,那麼接下來就是要對此語法樹進行處理,但考慮到不將處理操作與數據結構混合在一塊,我們需要一種方法將其分離。其實對於語法樹的處理最典型的處理模式就是訪問者模式,它能很好的將數據結構與處理分離,提供了很好的解耦作用,讓我們可以在生成語法樹的過程只需關注如何構建相關的數據結構,而在對語法樹處理的時候只需關注處理的邏輯,是一種非常巧的設計模式,接下來通過一個簡單的代碼案例看看如何實現一個訪問者模式。
①定義訪問者操作方法接口,聲明所有訪問者的操作方法。
public interface Visitor{
public void visit(RootNode rootNode);
public void visit(CommentNode commentNode);
public void visit(PageNode pageNode);
public void visit(IncludeNode includeNode);
public void visit(TaglibNode taglibNode);
}
②定義接口提供訪問入口,語法樹的每個節點都必須要實現此方法。
public interface NodeElement{
public void accept(Visitor v);
}
③不同類型的Node實現NodeElement接口,稍微改下原來定義的Node類,包括RootNode、CommentNode、PageNode、IncludeNode、TaglibNode,都添加accept方法。
public class RootNode implements NodeElement{
public void accept(Visitor v){
v.visit(this);
}
}
public class CommentNode implements NodeElement{
public void accept(Visitor v){
v.visit(this);
}
}
...
④現在假設我要按順序將語法樹中的注釋獲取出來,那麼我只需要實現一個獲取注釋的visitor,對於不同的處理邏輯只需實現不同的visitor即可,這裡由於對其他類型的節點不進行處理,所以其他節點的visit方法留空即可。
public class CommentVisitor implements Visitor{
public List
List
List
Iterator
while (iter.hasNext()) {
Node n = iter.next();
n.accept(this);
}
return comments;
}
public void visit(RootNode rootNode){}
public void visit(CommentNode commentNode){
comments.add(commentNode.getText());
}
public void visit(PageNode pageNode){}
public void visit(IncludeNode includeNode){}
public void visit(TaglibNode taglibNode){}
}
⑤測試類。
public class Test{
public static void main(String[] args){
RootNode root = Parser.parse();
CommentVisitor cv = new CommentVisitor();
List
}
}
通過上面一個簡單的例子可以看出訪問者模式將數據結構和處理邏輯很好地解耦出來了,這種模式很經常用在語法樹的解析處理上,熟悉此模式有助於對編譯過程的理解,JSP對語法的解析也是如此。