什么是解释器模式
解释器模式定义了一个语言的文法,并且建立一个解释器来解释语言中的句子。
解释器模式主要包含以下几个角色:
AbstractExpression(抽象表达式):声明了抽象的解释操作。
TerminalExpression(终结符表达式):抽象表达式的子类,实现了与文法中终结符相关的解释操作,文法中的每一个终结符都有一个终结表达式。
NonterminalExpression(非终结符表达式):抽象表达式的子类,实现了文法中非终结符相关的解释操作,由于在非终结符表达式中可以包含终结符表达式也可以包含非终结符表达式,因此解释操作一般是递归完成。
Context(环境):用于存储解释器之外的全局信息。
解释器模式的优缺点
优点
- 可以通过继承等方式改变和扩展文法。
- 每一个文法都可以表示为一个类,可以方便的实现一个语言。
- 方便的增加新的解释表达式。
缺点
- 对于复杂的文法可能需要定义过多的解释类,难以维护。
- 执行效率下,解释器模式中使用了大量的循环和递归调用,对于复杂的文法执行效率低。
解释器模式的应用场景
- 文法比较简单。
- 执行效率不是关键。
- 一些重复出现的问题可以用一种简单的语言来表达。
- 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
解释器模式的案例
// 抽象表达式
public abstract class Expression {
/**
* 解释公式和数值, key 就是公式(表达式) 参数[a,b,c], value就是就是具体值
*
* @param var var
* @return int
*/
public abstract int interpreter(HashMap<String, Integer> var);
}
// 解释器
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 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) {
return 0;
}
}
public class SubExpression extends SymbolExpression {
public SubExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) - super.right.interpreter(var);
}
}
public class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(HashMap<String, Integer> var) {
//super.left.interpreter(var) : 返回 left 表达式对应的值 a = 10
//super.right.interpreter(var): 返回right 表达式对应值 b = 20
return super.left.interpreter(var) + super.right.interpreter(var);
}
}
public class Calculator {
private Expression expression;
public Calculator(String expStr) {
// 安排运算先后顺序
Stack<Expression> stack = new Stack<>();
// 表达式拆分成字符数组
char[] charArray = expStr.toCharArray();
Expression left;
Expression right;
//遍历我们的字符数组, 即遍历 [a, +, b]
//针对不同的情况,做处理
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case '+':
// 从stack取出left => "a"
left = stack.pop();
// 取出右表达式 "b"
right = new VarExpression(String.valueOf(charArray[++i]));
// 然后根据得到left 和 right 构建 AddExpresson加入stack
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:
//如果是一个 Var 就创建要给 VarExpression 对象,并push到 stack
stack.push(new VarExpression(String.valueOf(charArray[i])));
break;
}
}
//当遍历完整个 charArray 数组后,stack 就得到最后Expression
this.expression = stack.pop();
}
public int run(HashMap<String, Integer> var) {
//最后将表达式a+b和 var = {a=10,b=20}
//然后传递给expression的interpreter进行解释执行
return this.expression.interpreter(var);
}
}
public static void main(String[] args) throws IOException {
String expStr = getExpStr();
HashMap<String, Integer> var = getValue(expStr);
Calculator calculator = new Calculator(expStr);
System.out.println("运算结果:" + expStr + "=" + calculator.run(var));
}
public static String getExpStr() throws IOException {
System.out.print("请输入表达式:");
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;
}

解释器模式在源码中的应用
SpelExpression
public interface Expression {
String getExpressionString();
@Nullable
Object getValue() throws EvaluationException;
@Nullable
<T> T getValue(@Nullable Class<T> desiredResultType) throws EvaluationException;
@Nullable
<T> T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException;
@Nullable
<T> T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException;
@Nullable
Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException;
@Nullable
TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
@Nullable
TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException;
......
}
public class SpelExpression implements Expression {
// Number of times to interpret an expression before compiling it
private static final int INTERPRETED_COUNT_THRESHOLD = 100;
// Number of times to try compiling an expression before giving up
private static final int FAILED_ATTEMPTS_THRESHOLD = 100;
private final String expression;
private final SpelNodeImpl ast;
@Override
@Nullable
public Object getValue() throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
EvaluationContext context = getEvaluationContext();
return compiledAst.getValue(context.getRootObject().getValue(), context);
}
catch (Throwable ex) {
// If running in mixed mode, revert to interpreted
if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
this.compiledAst = null;
this.interpretedCount.set(0);
}
else {
// Running in SpelCompilerMode.immediate mode - propagate exception to caller
throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
}
}
}
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
Object result = this.ast.getValue(expressionState);
checkCompile(expressionState);
return result;
}
......
}