本文實例講述了Java基於解釋器模式實現定義一種簡單的語言功能。分享給大家供大家參考,具體如下:
一模式定義
解釋器模式:就是給定一個語言的文法表示,並且定義一個解釋器,用來解釋語言中的句子。解釋器模式描述了怎樣在有了一個簡單的文法後,使用模式設計解釋這些語句。
二模式舉例
1 模式分析
我們自己設計一種語言來說明這一模式
(1)該語言區分大小寫(2)該語言以PROGRAM開頭,END結尾(3)PRINTLN表示打印一行並換行(4)使用FOR…FROM…TO…END表示循環
示例語言內容如下:
PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end...END
該句表示的意思是:首先打印“start…”換行,然後循環打印“90”換行、“91”換行、……“100”換行,最後打印“end…”換行。
2 該語言解釋樹結構
3 該語言解釋器活動圖
4 代碼示例
4.1 創建上下文環境――Context
package com.demo.interpreter.context;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.StringTokenizer;/** * 上下文環境* * @author * */public class Context { // 待解析的文本內容private final StringTokenizer stringTokenizer; // 當前命令private String currentToken; // 用來存儲動態變化信息內容private final Map<String, Object> map = new HashMap<String, Object>(); /** * 構造方法設置解析內容* * @param text */ public Context(String text) { // 使用空格分隔待解析文本內容this.stringTokenizer = new StringTokenizer(text); } /** * 解析文本*/ public String next() { if (this.stringTokenizer.hasMoreTokens()) { currentToken = this.stringTokenizer.nextToken(); } else { currentToken = null; } return currentToken; } /** * 判斷命令是否正確* * @param command * @return */ public boolean equalsWithCommand(String command) { if (command == null || !command.equals(this.currentToken)) { return false; } return true; } /** * 獲得當前命令內容* * @return */ public String getCurrentToken() { return this.currentToken; } /** * 獲得節點的內容* * @return */ public String getTokenContent(String text) { String str = text; if (str != null) { // 替換map中的動態變化內容後返回Iterator<String> // 替換map中的動態變化內容後返回Iterator<String> iterator = this.map.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); Object obj = map.get(key); str = str.replaceAll(key, obj.toString()); } } return str; } public void put(String key, Object value) { this.map.put(key, value); } public void clear(String key) { this.map.remove(key); }}4.2 表達式接口――IExpressions
package com.demo.interpreter.express;import com.demo.interpreter.context.Context;/** * * 表達式接口* * @author * */public interface IExpressions { /** * 解析* * @param context */ public void parse(Context context); /** * 執行方法* * @param context */ public void interpret();}4.3 主表達式――ProgramExpression
package com.demo.interpreter.express;import com.demo.interpreter.context.Context;/** * program 表達式* * @author * */public class ProgramExpression implements IExpressions { // 上下文環境private final Context context; // 當前命令private final static String COMMAND = "PROGRAM"; // 存儲下一個表達式引用private IExpressions expressions; /** * 構造方法將待解析的內容傳入* * @param text */ public ProgramExpression(String text) { this.context = new Context(text); this.parse(this.context); } @Override public void parse(Context context) { // 獲取第一個命令節點this.context.next(); } /** * 實現解釋方法*/ @Override public void interpret() { // 判斷是否是以PROGRAM 開始if (!this.context.equalsWithCommand(COMMAND)) { System.out.println("The '" + COMMAND + "' is Excepted For Start!"); } else { // 是以PROGRAM 開始this.context.next(); this.expressions = new ListExpression(); this.expressions.parse(this.context); // ListExpression表達式開始解析this.expressions.interpret(); } }}4.4 列表表達式――ListExpression
package com.demo.interpreter.express;import java.util.ArrayList;import java.util.Iterator;import com.demo.interpreter.context.Context;/** * 列表表達式* * @author * */public class ListExpression implements IExpressions { private Context context; private final ArrayList<IExpressions> list = new ArrayList<IExpressions>(); /** * 構造方法將待解析的context傳入* * @param context */ public void parse(Context context) { this.context = context; // 在ListExpression解析表達式中,循環解釋語句中的每一個單詞,直到終結符表達式或者異常情況退出while (true) { if (this.context.getCurrentToken() == null) { // 獲取當前節點如果為null 則表示缺少END表達式System.out.println("Error: The Experssion Missing 'END'! "); break; } else if (this.context.equalsWithCommand("END")) { this.context.next(); // 解析正常結束break; } else { // 建立Command 表達式IExpressions expressions = new CommandExperssion(this.context); // 添加到列表中list.add(expressions); } } } /** * 實現解釋方法*/ @Override public void interpret() { // 循環list列表中每一個表達式解釋執行Iterator<IExpressions> iterator = list.iterator(); while (iterator.hasNext()) { (iterator.next()).interpret(); } }}4.5 命令表達式――CommandExperssion
package com.demo.interpreter.express;import com.demo.interpreter.context.Context;/** * 命令表達式* * @author * */public class CommandExperssion implements IExpressions { private final Context context; private IExpressions expressions; /** * 構造方法將待解析的context傳入* * @param context */ public CommandExperssion(Context context) { this.context = context; this.parse(this.context); } public void parse(Context context) { // 判斷當前命令類別在此只對For和最原始命令進行區分if (this.context.equalsWithCommand("FOR")) { // 創建For表達式進行解析expressions = new ForExpression(this.context); } else { // 創建原始命令表達式進行內容解析expressions = new PrimitiveExpression(this.context); } } /** * 解析內容*/ @Override public void interpret() { // 解析內容this.expressions.interpret(); }}4.6 循環表達式――ForExpression
package com.demo.interpreter.express;import com.demo.interpreter.context.Context;/** * For表達式* * @author * */public class ForExpression implements IExpressions { private final Context context; // 存儲當前索引key值private String variable; // 存儲循環起始位置private int start_index; // 存儲循環結束位置private int end_index; private IExpressions expressions; /** * 構造方法將待解析的context傳入* * @param context */ public ForExpression(Context context) { this.context = context; this.parse(this.context); } /** * 解析表達式*/ @Override public void parse(Context context) { // 首先獲取當前節點this.context.next(); while (true) { // 判斷節點if (this.context.equalsWithCommand("FROM")) { // 設置開始索引內容String nextStr = this.context.next(); try { this.start_index = Integer.parseInt(nextStr); } catch (Exception e) { System.out .println("Error: After 'FROM' Expression Exist Error!Please Check the Format Of Expression is Correct!"); break; } // 獲取下一個節點this.context.next(); } else if (this.context.equalsWithCommand("TO")) { // 設置結束索引內容String nextStr = this.context.next(); try { this.end_index = Integer.parseInt(nextStr); } catch (Exception e) { System.out .println("Error: After 'TO' Expression Exist Error!Please Check the Format Of Expression is Correct!"); } this.context.next(); break; } else { // 設置當前索引變量內容if (this.variable == null) { this.variable = this.context.getCurrentToken(); } // 獲取下一個節點this.context.next(); } } // 建立列表表達式this.expressions = new ListExpression(); this.expressions.parse(this.context); } /** * 實現解釋方法*/ @Override public void interpret() { // 建立命令表達式for (int x = this.start_index; x <= this.end_index; x++) { // 設置變量內容this.context.put("" + this.variable, x); // 執行解釋方法this.expressions.interpret(); } // 移除使用的臨時變量內容this.context.clear("" + this.variable); }}4.7 基礎表達式――PrimitiveExpression
package com.demo.interpreter.express;import com.demo.interpreter.context.Context;/** * 最基礎的表達式* * @author * */public class PrimitiveExpression implements IExpressions { private Context context; // 節點名稱private String tokenName; // 文本內容private String text; /** * 構造方法將待解析的context傳入* * @param context */ public PrimitiveExpression(Context context) { this.parse(context); } @Override public void parse(Context context) { this.context = context; this.tokenName = this.context.getCurrentToken(); this.context.next(); if ("PRINTLN".equals(this.tokenName)) { this.text = this.context.getCurrentToken(); this.context.next(); } } /** * 實現解釋方法*/ @Override public void interpret() { // 首先獲取當前節點內容if ("PRINTLN".equals(tokenName)) { // 獲得內容信息// 打印內容System.out.println(this.context.getTokenContent(this.text)); } }}4.8 讓語言解釋器開始工作――Client
package com.demo.interpreter;import com.demo.interpreter.express.IExpressions;import com.demo.interpreter.express.ProgramExpression;/** * 主應用程序* * @author * */public class Client { /** * @param args */ public static void main(String[] args) { // myida語言語句String str = "PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END"; System.out.println("str:" + str); // 創建PROGRAM表達式IExpressions expressions = new ProgramExpression(str); // 解釋執行expressions.interpret(); }}5 運行結果
str:PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END
start...
90
91
92
93
94
95
96
97
98
99
100
end...
三設計原則
1 “開-閉”原則
2 封閉變化原則
四使用場合
(1)一種特定類型的問題發生的頻率足夠高,並且業務規則頻繁變化,不斷重複出現類似情況。
(2)業務規則不是過於復雜煩瑣,比較容易抽像出語法規則。
(3)效率不是軟件系統中主要考慮的因素。
五解釋器模式靜態類圖
更多java相關內容感興趣的讀者可查看本站專題:《Java面向對象程序設計入門與進階教程》、《Java數據結構與算法教程》、《Java操作DOM節點技巧總結》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對大家java程序設計有所幫助。