文法樹可以了解成是一種資料結構,假如某些語句已經被解析成一棵文法樹,那麼接下來就是要對此文法樹進行處理,但考慮到不将處理操作與資料結構混合在一塊,我們需要一種方法将其分離。其實對于文法樹的處理最典型的處理模式就是通路者模式,它能很好的将資料結構與處理分離,提供了很好的解耦作用,讓我們可以在生成文法樹的過程隻需關注如何建構相關的資料結構,而在對文法樹處理的時候隻需關注處理的邏輯,是一種非常巧的設計模式,接下來通過一個簡單的代碼案例看看如何實作一個通路者模式。
①定義通路者操作方法接口,聲明所有通路者的操作方法。
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{
...
④現在假設我要按順序将文法樹中的注釋擷取出來,那麼我隻需要實作一個擷取注釋的visitor,對于不同的處理邏輯隻需實作不同的visitor即可,這裡由于對其他類型的節點不進行處理,是以其他節點的visit方法留白即可。
public class CommentVisitor implements Visitor{
public List<String> getComments(rootNode){
List<String> comments = new ArrayList();
List<Node> nodes = rootNode.getNodes();
Iterator<Node> iter = nodes.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<String> comments = cv.getComments();
通過上面一個簡單的例子可以看出通路者模式将資料結構和處理邏輯很好地解耦出來了,這種模式很經常用在文法樹的解析處理上,熟悉此模式有助于對編譯過程的了解,JSP對文法的解析也是如此。
<a target="_blank" href="https://item.jd.com/12185360.html">點選訂購作者《Tomcat核心設計剖析》</a>