設計模式之直譯器模式
阿新 • • 發佈:2020-08-18
設計模式之直譯器模式
直譯器模式:是一種按照規定語法進行解析的方案,在現在專案中使用較少 ,給定一門語言,定義它的規則的一種表示式,並定義一個直譯器,該直譯器使用該表示式來解釋語言中的句子。
用的比較少,瞭解即可
2.直譯器模式例子:
例子:輸入一個模型公式(加、減運算),然後輸入模型中的引數,運算出結果。
3.程式碼
3.1 建立一個Expression表示式類
public abstract class Expression { /** * 抽象表示式,用來解析表示式的值 * map的key表示具體的變數。value表示變數的值 * * @param map * @return */ public abstract int interpreter(Map<String, Integer> map); }
3.2 建立一個變數解析器
public class VarExpression extends Expression { private String key; public VarExpression(String key) { this.key = key; } // 獲取具體變數的值 @Override public int interpreter(Map<String, Integer> map) { return map.get(key); } }
3.3 抽象運算子號解析器
public abstract class SymbolExpression extends Expression { protected Expression left; protected Expression right; public SymbolExpression(Expression left, Expression right) { System.out.println("呼叫了symbolExpression中的方法=========>left " + left + "=========>" + "right: " + right + " "); this.left = left; this.right = right; } }
3.4 加法解析器
public class AddExpression extends SymbolExpression { public AddExpression(Expression left, Expression right) { super(left, right); } @Override public int interpreter(Map<String, Integer> map) { int result = super.left.interpreter(map) + super.right.interpreter(map); System.out.println(" add中的result============>" + result + " "); return result; } }
3.5 減法解析器
public class SubExpression extends SymbolExpression { public SubExpression(Expression left, Expression right) { super(left, right); } @Override public int interpreter(Map<String, Integer> map) { int subresult = super.left.interpreter(map) - super.right.interpreter(map); System.out.println(" sub計算結果=======>" + subresult + " "); return subresult; } }
3.6 建立解析器封裝器
public class Calculator { private Expression expression; public Calculator(String expStr) { // 定義一個棧,安排執行的先後執行 Stack<Expression> stack = new Stack<>(); // 表示式拆分為位元組資料 char[] charArray = expStr.toCharArray(); Expression left; Expression right; for (int i = 0; i < charArray.length; i++) { switch (charArray[i]) { case '+': left = stack.pop(); right = new VarExpression(String.valueOf(charArray[++i])); stack.push(new AddExpression(left, right)); System.out.println("left: " + left + " right==>" + right + " stack中的值======>" + stack.toString()); break; case '-': left = stack.pop(); right = new VarExpression(String.valueOf(charArray[++i])); stack.push(new SubExpression(left, right)); System.out.println("left: " + left + " right==>" + right + " stack中的值======>" + stack.toString()); break; default: // 公式中的變數 stack.push(new VarExpression(String.valueOf(charArray[i]))); System.out.println("stack中的值======>" + stack.toString()); } } // 把運算結果丟擲來 this.expression = stack.pop(); } // 開始運算 public int run(HashMap<String, Integer> map) { return this.expression.interpreter(map); } }
3.7 客戶端程式碼
public class Client { public static void main(String[] args) throws Exception { String expStr = getExpStr(); Calculator calculator = new Calculator(expStr); // 賦值 HashMap<String, Integer> var = getVar(expStr); System.out.println("運算結果為:" + expStr + "=" + calculator.run(var)); } private static HashMap<String, Integer> getVar(String expStr) throws Exception { HashMap<String, Integer> hashMap = new HashMap<String, Integer>(); // 解析幾個引數要傳遞 for (char ch : expStr.toCharArray()) { if (ch != '+' && ch != '-') { // 解決重複引數的問題 if (!hashMap.containsKey(String.valueOf(ch))) { System.out.println("請輸入變數" + ch + "的值: "); String in = (new BufferedReader(new InputStreamReader(System.in))).readLine(); hashMap.put(String.valueOf(ch), Integer.valueOf(in)); } } } return hashMap; } private static String getExpStr() throws IOException { System.out.println("請輸入表示式"); return (new BufferedReader(new InputStreamReader(System.in))).readLine(); } }
執行截圖:
4.直譯器的優點:
直譯器是一個簡單語法分析工具,它最顯著的優點就是擴充套件性,修改語法規則只要修改相應的表示式就可以了,若擴充套件語法,則只要增加規則類就可以了,例如add,sub。
5.直譯器的缺點
- 直譯器模式會引起類膨脹:一個規則加一個類
- 直譯器模式採用遞迴呼叫方法:如果程式報錯了,一步步除錯下去,非常複雜
- 效率問題:直譯器模式由於使用了大量的迴圈和遞迴,效率是一個不容忽視的問題,特別是一用於解析複雜、冗長的語法時,效率是難以忍受的。
6.直譯器的應用場景
- 重複發生的問題可以使用直譯器模式
- 一個簡單語法需要解釋的場景
7.直譯器模式注意事項
儘量不要在重要的模組中使用直譯器模式,否則維護會是一個很大的問題。在專案中可以使用shell、JRuby、Groovy等指令碼語言來代替直譯器模式,彌補Java編譯型語言的不足。我所在公司是金融證券公司,涉及到很多業務型別的計算場景。我們的計算元件採用的時候MVEL表示式的方式進行計算,使用起來美滋滋的。準備使用直譯器模式的時候,可以百度搜一下Expression4J、MESP(Math Expression String Parser)、Jep等開源的解析工具包。功能都異常強大,而且非常容易使用,效率也還不錯,實現大多數的數學運算完全沒有問題。總之,就是有大佬開發的現成的工具,直接拿來用就好了