解釋器模式提供了一種評估計算語言語法或表達式的方法。 這種類型的模式屬於行爲模式。 這種設計模式涉及實現一個表達式接口,它告訴解釋一個指定的上下文。 此模式用於SQL解析,符號處理引擎等。node
解釋器模式包含如下主要角色。設計模式
//環境類:用於存儲和操做須要解釋的語句,在本實例中每個須要解釋的單詞能夠稱爲一個動做標記(Action Token)或命令 class Context { private StringTokenizer tokenizer; //StringTokenizer類,用於將字符串分解爲更小的字符串標記(Token),默認狀況下以空格做爲分隔符 private String currentToken; //當前字符串標記 public Context(String text) { tokenizer = new StringTokenizer(text); //經過傳入的指令字符串建立StringTokenizer對象 nextToken(); } //返回下一個標記 public String nextToken() { if (tokenizer.hasMoreTokens()) { currentToken = tokenizer.nextToken(); } else { currentToken = null; } return currentToken; } //返回當前的標記 public String currentToken() { return currentToken; } //跳過一個標記 public void skipToken(String token) { if (!token.equals(currentToken)) { System.err.println("錯誤提示:" + currentToken + "解釋錯誤!"); } nextToken(); } //若是當前的標記是一個數字,則返回對應的數值 public int currentNumber() { int number = 0; try { number = Integer.parseInt(currentToken); //將字符串轉換爲整數 } catch (NumberFormatException e) { System.err.println("錯誤提示:" + e); } return number; } } //抽象節點類:抽象表達式 abstract class Node { public abstract void interpret(Context text); //聲明一個方法用於解釋語句 public abstract void execute(); //聲明一個方法用於執行標記對應的命令 } //表達式節點類:非終結符表達式 class ExpressionNode extends Node { private ArrayList<Node> list = new ArrayList<Node>(); //定義一個集合用於存儲多條命令 public void interpret(Context context) { //循環處理Context中的標記 while (true) { //若是已經沒有任何標記,則退出解釋 if (context.currentToken() == null) { break; } //若是標記爲END,則不解釋END並結束本次解釋過程,能夠繼續以後的解釋 else if (context.currentToken().equals("END")) { context.skipToken("END"); break; } //若是爲其餘標記,則解釋標記並將其加入命令集合 else { Node commandNode = new CommandNode(); commandNode.interpret(context); list.add(commandNode); } } } //循環執行命令集合中的每一條命令 public void execute() { Iterator iterator = list.iterator(); while (iterator.hasNext()) { ((Node) iterator.next()).execute(); } } } //語句命令節點類:非終結符表達式 class CommandNode extends Node { private Node node; public void interpret(Context context) { //處理LOOP循環命令 if (context.currentToken().equals("LOOP")) { node = new LoopCommandNode(); node.interpret(context); } //處理其餘基本命令 else { node = new PrimitiveCommandNode(); node.interpret(context); } } public void execute() { node.execute(); } } //循環命令節點類:非終結符表達式 class LoopCommandNode extends Node { private int number; //循環次數 private Node commandNode; //循環語句中的表達式 //解釋循環命令 public void interpret(Context context) { context.skipToken("LOOP"); number = context.currentNumber(); context.nextToken(); commandNode = new ExpressionNode(); //循環語句中的表達式 commandNode.interpret(context); } public void execute() { for (int i = 0; i < number; i++) commandNode.execute(); } } //基本命令節點類:終結符表達式 class PrimitiveCommandNode extends Node { private String name; private String text; //解釋基本命令 public void interpret(Context context) { name = context.currentToken(); context.skipToken(name); if (!name.equals("PRINT") && !name.equals("BREAK") && !name.equals("SPACE")) { System.err.println("非法命令!"); } if (name.equals("PRINT")) { text = context.currentToken(); context.nextToken(); } } public void execute() { if (name.equals("PRINT")) System.out.print(text); else if (name.equals("SPACE")) System.out.print(" "); else if (name.equals("BREAK")) System.out.println(); } }
客戶端測試代碼工具
class Client { public static void main(String[] args) { String text = "LOOP 2 PRINT 楊過 SPACE SPACE PRINT 小龍女 BREAK END PRINT 郭靖 SPACE SPACE PRINT 黃蓉"; Context context = new Context(text); Node node = new ExpressionNode(); node.interpret(context); node.execute(); } }
在本實例代碼中,環境類 Context 相似一個工具類,它提供了用於處理指令的方法,如 nextToken()、currentToken()、skipToken() 等,同時它存儲了須要解釋的指令並記錄了每一次解釋的當前標記(Token),而具體的解釋過程交給表達式解釋器類來處理。咱們還能夠將各類解釋器類包含的公共方法移至環境類中,更好地實現這些方法的重用和擴展。oop
優勢:測試
解釋器是一個簡單語法分析工具,它最顯著的優勢就是擴展性,修改語法規則只要修改相應的非終結符表達式就能夠了,若擴展語法,則只要增長非終結符類就能夠了。spa
缺點:設計
每一個語法都要產生一個非終結符表達式,語法規則比較複雜時,就可能產生大量的類文件,爲維護帶來了很是多的麻煩。調試
解釋器模式採用遞歸調用方法,若是要排查一個語法錯誤,要一個一個斷點的調試下去,會很麻煩。code
解釋器模式使用了大量的循環和遞歸,特別是用於解析複雜、冗長的語法時,效率會很低。orm
……更多設計模式的內容,能夠訪問Refactoring.Guru