簡介
1.在編譯原理中,一個算數(shù)表達(dá)式通常是詞法分析器形成詞法單元,而后這些詞法單元在通過 語法分析器 構(gòu)建語法分析樹,最終形成一個抽象的語法分析樹.這里的詞法分析器和語法分析器都可以看成是解釋器
2.解釋器模式(Interpreter Pattern):是指定一個語言(表達(dá)式),定義它的文法的一種表示,并定義一個解釋器,使用該解釋器來解釋語言中的句子(表達(dá)式)
3.應(yīng)用場景
- 應(yīng)用可以將一個需要執(zhí)行的語言中的句子表示為一個抽象語法樹.
- 一些重復(fù)出現(xiàn)的問題可以用一種簡單的語言來表達(dá)
- 一個簡單的語法需要解釋的場景
4.這樣的例子還有:比如編譯器.運(yùn)算表達(dá)式,正則表達(dá)式,機(jī)器人等
原理類圖與角色分析
1.類圖
2.角色分析
Context:是環(huán)境角色,含有解釋器之外的全局信息
AbstractExpression:抽象表達(dá)式,聲明一個抽象的解釋操作,這個方法為抽象語法樹中所有節(jié)點(diǎn)共享
TerminalExpression: 為終結(jié)者表達(dá)式.實現(xiàn)與文法中的終結(jié)符相關(guān)的解釋操作
NoTerminalExpression : 為非終結(jié)者表達(dá)式,為文法中的非終結(jié)符實現(xiàn)的解釋操作
說明:輸入Context 和 TerminalExpression信息通過Cilent 輸入即可
案例分析 四則運(yùn)算問題
通過解釋器模式來實現(xiàn)四則運(yùn)算,如計算 a+b-c 的值 具體要求
1.先輸入表達(dá)式的形式 比如 a+b+c-d-e 要求表達(dá)式的字母不能重復(fù),
2,分別輸入 a,b,c,d,e 的值
3.然后計算出結(jié)果
問題分析
1.編寫一個方法,接收表達(dá)式的形式,然后根據(jù)用戶輸入的數(shù)值進(jìn)行解析計算,得到結(jié)果
2.問題分析:如果輸入新的運(yùn)算符.比如 / * 等等 不利于拓展 另外一個方法來解析會造成程序結(jié)構(gòu)混亂
3.解決方案:可以考慮使用解釋器模式 即 : 表達(dá)式 ==>> 解釋器 (可以有多種) ==>> 結(jié)果
解釋器模式實現(xiàn)四則運(yùn)算
1.思路和圖解分析
2.代碼實現(xiàn)
public class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) + super.right.interpreter(var);
}
}
public class Calculator {
// 定義表達(dá)式
private Expression expression;
// 構(gòu)造函數(shù)傳參脐区,并解析
public Calculator(String expStr) {
// 安排運(yùn)算先后順序
Stack<Expression> stack = new Stack<>();
char[] charArray = expStr.toCharArray();
Expression left = null;
Expression right = null;
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));//
break;
case '-': //
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new SubExpression(left, right));
break;
default:
stack.push(new VarExpression(String.valueOf(charArray[i])));
break;
}
}
this.expression = stack.pop();
}
public int run(HashMap<String, Integer> var) {
return this.expression.interpreter(var);
}
}
public abstract class Expression {
public abstract int interpreter(HashMap<String, Integer> var);
}
public class SubExpression extends SymbolExpression {
public SubExpression(Expression left, Expression right) {
super(left, right);
}
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) - super.right.interpreter(var);
}
}
/**
* 抽象運(yùn)算符號解析器 這里阔逼,每個運(yùn)算符合都只和自己左右兩個數(shù)字有關(guān)系,
* 但左右兩個數(shù)字有可能也是一個解析的結(jié)果渠旁,無論何種類型,都是Expression類的實現(xiàn)類
*
* @author Administrator
*
*/
public class SymbolExpression extends Expression {
protected Expression left;
protected Expression right;
public SymbolExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpreter(HashMap<String, Integer> var) {
// TODO Auto-generated method stub
return 0;
}
}
public class VarExpression extends Expression {
private String key;
public VarExpression(String key) {
this.key = key;
}
@Override
public int interpreter(HashMap<String, Integer> var) {
return var.get(this.key);
}
}
測試
public class ClientTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String expStr = getExpStr();
HashMap<String, Integer> var = getValue(expStr);
Calculator calculator = new Calculator(expStr);
System.out.println("運(yùn)算結(jié)果:" + expStr + "=" + calculator.run(var));
}
// 獲得表達(dá)式
public static String getExpStr() throws IOException {
System.out.print("請輸入表達(dá)式:");
return (new BufferedReader(new InputStreamReader(System.in))).readLine();
}
// 獲得值映射
public static HashMap<String, Integer> getValue(String expStr) throws IOException {
HashMap<String, Integer> map = new HashMap<>();
for (char ch : expStr.toCharArray()) {
if (ch != '+' && ch != '-') {
if (!map.containsKey(String.valueOf(ch))) {
System.out.print("請輸入" + String.valueOf(ch) + "的值:");
String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
map.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return map;
}
}
測試結(jié)果
請輸入表達(dá)式:a+b+c-d-e
請輸入a的值:10
請輸入b的值:50
請輸入c的值:12
請輸入d的值:78
請輸入e的值:20
運(yùn)算結(jié)果:a+b+c-d-e=-26
解釋器設(shè)計模式在Spring框架應(yīng)用的源碼分析
1.Spring框架中,SpelExpressionParser 就使用到解釋器模式
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
public class Interpreter {
public static void main(String[] args) {
// TODO Auto-generated method stub
//創(chuàng)建一個 Parser 對象
SpelExpressionParser parser = new SpelExpressionParser();
//
//通過 Parser 對象 獲取到一個Expression對象
//會根據(jù)不同的 Parser 對象 船逮,返回不同的 Expression對象
Expression expression = parser.parseExpression("10 * (2 + 1) * 1 + 66"); //96
int result = (Integer) expression.getValue();
System.out.println(result);
}
}
解釋器模式的注意事項和細(xì)節(jié)
1.當(dāng)有一個語言需要解釋執(zhí)行.可將該語言中的句子表示為一個抽象語法樹,就可以考慮使用編譯器模式,讓程序具有良好的拓展性
2.應(yīng)用場景:編譯器,運(yùn)算表達(dá)式計算.正則表達(dá)式,機(jī)器人等
3.使用解釋器可能帶來的問題:解釋器模式會引起類膨脹,解釋器模式采用遞歸調(diào)用方法,將會導(dǎo)致調(diào)試程序非常復(fù)雜,效率可能降低