设计模式 | 解释器模式及典型应用 (2)

实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。

增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合 "开闭原则"。

主要缺点

对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。

执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

适用场景

可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。

一些重复出现的问题可以用一种简单的语言来进行表达。

一个语言的文法较为简单。

对执行效率要求不高。

解释器模式的典型应用 Spring EL表达式中的解释器模式

Spring EL表达式相关的类在 org.springframework.expression 包下,类图如下

涉及的类非常多,这里仅对此时我们最关心的几个类做介绍:

SpelExpression,表示一个 EL 表达式,表达式在内部通过一个 AST抽象语法树 表示,EL表达式求值是通过 this.ast.getValue(expressionState); 求值

public class SpelExpression implements Expression { private final String expression; private final SpelNodeImpl ast; private final SpelParserConfiguration configuration; @Override @Nullable public Object getValue() throws EvaluationException { if (this.compiledAst != null) { try { EvaluationContext context = getEvaluationContext(); return this.compiledAst.getValue(context.getRootObject().getValue(), context); } catch (Throwable ex) { // If running in mixed mode, revert to interpreted if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { this.interpretedCount = 0; this.compiledAst = null; } 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; } //...省略... }

SpelNodeImpl:已解析的Spring表达式所代表的ast语法树的节点的通用父类型,语法树的节点在解释器模式中扮演的角色是终结符和非终结符。从类图中可以看到,SpelNodeImpl 的子类主要有 Literal,Operator,Indexer等,其中 Literal 是各种类型的值的父类,Operator 则是各种操作的父类

public abstract class SpelNodeImpl implements SpelNode, Opcodes { protected int pos; // start = top 16bits, end = bottom 16bits protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN; @Nullable private SpelNodeImpl parent; public final Object getValue(ExpressionState expressionState) throws EvaluationException { return getValueInternal(expressionState).getValue(); } // 抽象方法,由子类实现,获取对象的值 public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException; //...省略... }

IntLiteral 表示整型文字的表达式语言的ast结点

public class IntLiteral extends Literal { private final TypedValue value; public IntLiteral(String payload, int pos, int value) { super(payload, pos); this.value = new TypedValue(value); // this.exitTypeDescriptor = "I"; } @Override public TypedValue getLiteralValue() { return this.value; } // ... }

OpPlus 表示加法的ast结点,在 getValueInternal 方法中对操作符两边进行相加操作

public class OpPlus extends Operator { public OpPlus(int pos, SpelNodeImpl... operands) { super("+", pos, operands); Assert.notEmpty(operands, "Operands must not be empty"); } @Override public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { SpelNodeImpl leftOp = getLeftOperand(); if (this.children.length < 2) { // if only one operand, then this is unary plus Object operandOne = leftOp.getValueInternal(state).getValue(); if (operandOne instanceof Number) { if (operandOne instanceof Double) { this.exitTypeDescriptor = "D"; } else if (operandOne instanceof Float) { this.exitTypeDescriptor = "F"; } else if (operandOne instanceof Long) { this.exitTypeDescriptor = "J"; } else if (operandOne instanceof Integer) { this.exitTypeDescriptor = "I"; } return new TypedValue(operandOne); } return state.operate(Operation.ADD, operandOne, null); } // 递归调用leftOp的 getValueInternal(state) ,获取操作符左边的值 TypedValue operandOneValue = leftOp.getValueInternal(state); Object leftOperand = operandOneValue.getValue(); // 递归调用children[1]的 getValueInternal(state) ,获取操作符右边的值 TypedValue operandTwoValue = getRightOperand().getValueInternal(state); Object rightOperand = operandTwoValue.getValue(); // 如果操作符左右都是数值类型,则将它们相加 if (leftOperand instanceof Number && rightOperand instanceof Number) { Number leftNumber = (Number) leftOperand; Number rightNumber = (Number) rightOperand; if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) { BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class); BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class); return new TypedValue(leftBigDecimal.add(rightBigDecimal)); } else if (leftNumber instanceof Double || rightNumber instanceof Double) { this.exitTypeDescriptor = "D"; return new TypedValue(leftNumber.doubleValue() + rightNumber.doubleValue()); } //...省略 Float->F, BigInteger->add, Long->J,Integer->I else { // Unknown Number subtypes -> best guess is double addition return new TypedValue(leftNumber.doubleValue() + rightNumber.doubleValue()); } } //... return state.operate(Operation.ADD, leftOperand, rightOperand); } //... }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzsjx.html