簡介 解釋器模式(Interpreter Pattern)是一種行為型設計模式。這種模式實現了一個表達式介面,該介面解釋一個特定的上下文。這種模式常被用在 SQL 解析、符號處理引擎等。 解釋器模式常用於對簡單語言的編譯或分析實例中,為了掌握好它的結構與實現,必須先瞭解編譯原理中的“文法、句子、語法 ...
簡介
解釋器模式(Interpreter Pattern)是一種行為型設計模式。這種模式實現了一個表達式介面,該介面解釋一個特定的上下文。這種模式常被用在 SQL 解析、符號處理引擎等。
解釋器模式常用於對簡單語言的編譯或分析實例中,為了掌握好它的結構與實現,必須先瞭解編譯原理中的“文法、句子、語法樹”等相關概念。
作用
- 可擴展性比較好,靈活,增加了新的解釋表達式的方式,易於實現簡單文法。
- 在語法樹中的每個表達式節點類都是相似的,所以實現其文法較為容易。
實現步驟
- 創建抽象表達式介面(Expression),各種表達式都要實現該介面。
- 分別創建最終表達式和非最終表達式。最終表達式(這裡是VarExpression)沒有子級,直接解釋表達式。非最終表達式(這裡是AddExpression和SubtractExpression)是維護子表達式的容器,並將解釋請求轉發給這些表達式。
- 創建上下文環境類(這裡是Context),用來表達式求值時構建執行環境。
- 客戶端調用時先建立執行上下文環境,然後聲明變數,再進行計算。
UML
Java代碼
抽象表達式介面
// Expression.java 抽象表達式介面,根據業務場景規範表達式
public interface Expression {
public int interpret(Context context);
}
具體表達式實現
// AddExpression.java 具體表達式,實現了抽象表達式介面
public class AddExpression implements Expression {
private Expression exprOne = null;
private Expression exprTwo = null;
public AddExpression(Expression exprOne, Expression exprTwo) {
this.exprOne = exprOne;
this.exprTwo = exprTwo;
}
// 覆蓋表達式,執行context對象
@Override
public int interpret(Context context) {
System.out.println(this.getClass().getName() + "::interpret() [context = " + context.getClass().getName() + "]");
return exprOne.interpret(context) + exprTwo.interpret(context);
}
}
// SubtractExpression.java 具體表達式,實現了抽象表達式介面
public class SubtractExpression implements Expression {
private Expression exprOne = null;
private Expression exprTwo = null;
public SubtractExpression(Expression exprOne, Expression exprTwo) {
this.exprOne = exprOne;
this.exprTwo = exprTwo;
}
// 覆蓋表達式,執行context對象
@Override
public int interpret(Context context) {
System.out.println(this.getClass().getName() + "::interpret() [context = " + context.getClass().getName() + "]");
return exprOne.interpret(context) - exprTwo.interpret(context);
}
}
// VarExpression.java 變數表達式,或者叫終端表達式,其他表達式求值時通過層層追溯最後指向這裡
// 變數與執行環境的Key對應,最終會通過key獲取傳入的值
public class VarExpression implements Expression {
private String key;
public VarExpression(String key) {
this.key = key;
}
@Override
// 覆蓋表達式,根據key獲取變數
public int interpret(Context context) {
return context.get(key);
}
}
執行環境類
// Context.java 構建可執行環境上下文
public class Context {
private Map<String, Integer> map = new HashMap<>();
public Context(String key, int value) {
this.add(key, value);
}
public Context() {
}
public void add(String key, int value) {
map.put(key, value);
}
public int get(String key) {
return map.get(key);
}
}
// Application.java 調用程式,組織各種解釋器
/*
* 解釋器模式先構建執行上下文Context,然後構建一個最終的獲取值的表達式VarExpression,這就構成了含上下文和變數-值的基本環境。
* 再將基本環境放到工具表達式里AddExpression或SubtractExpreesion進行計算,最終得到結果。
*/
// 構建兩個數相加的例子
public static int addTwo(int one, int two) {
// 構建執行上下文環境
Context context = new Context();
context.add("one", one);
context.add("two", two);
// 構建表達式
VarExpression varOne = new VarExpression("one");
VarExpression varTwo = new VarExpression("two");
// 再構建變數來進行計算,看起來啰嗦,但這樣構建多種不同表達式計算就變得簡單
Expression result = new AddExpression(varOne, varTwo);
return result.interpret(context);
}
// 構建連加計算的例子
public static int addMore(int... numbers) {
if (numbers.length <= 1) {
return numbers[0];
}
Context context = new Context();
// 構建執行環境
for (int num : numbers) {
context.add("num" + num, num);
}
// 先取出前兩個作為計算基礎
VarExpression varOne = new VarExpression("num" + numbers[0]);
VarExpression varTwo = new VarExpression("num" + numbers[1]);
// 再構建表達式,先賦值前兩個
Expression expression = new AddExpression(varOne, varTwo);
// 如果只有兩個數則直接返回計算結果
if (numbers.length == 2) {
return expression.interpret(context);
}
// 如果數量超過兩個則累加表達式再求值
for (int i = 2; i < numbers.length; i++) {
Expression nextExpression = new VarExpression("num" + numbers[i]);
// 表達式不斷累加
expression = new AddExpression(expression, nextExpression);
}
return expression.interpret(context);
}
// 計算前兩個數相加,再減去後一個數的計算例子
public static int addAndSubtract(int one, int two, int three) {
// 構建執行上下文環境,有3個可操作的域
Context context = new Context();
context.add("one", one);
context.add("two", two);
context.add("three", three);
// 構建表達式,有3個變數