写点什么

InterpreterPattern- 解释器模式

作者:梁歪歪 ♚
  • 2022 年 6 月 06 日
  • 本文字数:3092 字

    阅读完需:约 10 分钟

InterpreterPattern-解释器模式

解释器模式

解释器模式(Interpreter Pattern):是指给定一门语言,定义它的文法的一种表示(如:加减乘除表达式和正则表达式等),然后再定义一个解释器,该解释器用来解释我们的文法表示(表达式)。


解释器模式是一种按照规定的语法来进行解析的一种设计模式,属于行为型模式。


终结符表达式和非终结符表达式


  • 终结符表达式(Terminal Expression):实现文法中与终结符有关的解释操作。文法中每一个终结符都有一个具体的终结符表达式与之相对应。比如我们的 R=M+N 运算,M 和 N 就是终结符,对应的解析 M 和 N 的解释器就是终结符表达式。

  • 非终符结表达式(Nonterminal Expression):实现文法中与非终结符有关的解释操作。文法中的每一条规则都对应了一个非终结符表达式。非终结表达式一般是文法中的运算符或者关键字,如上面公示:R=M+N 中的“+”号就是非终结符,解析“+”号的解释器就是一个非终结符表达式。


示例:我们通过简单的加减法表达式进行举例说明...


  • 顶层的表达式接口IExpression.java


package cn.liangyy.interpreter;
/** * 顶层的表达式接口 */public interface IExpression { /** * 用来解释表达式的方法 * @return */ int interpret();}
复制代码


  • 抽象的非终结表达式AbstractNonTerminalExpression.java


package cn.liangyy.interpreter;
/** * 非终结表达式-抽象表达式 */public abstract class AbstractNonTerminalExpression implements IExpression { //非终结表达式左边表达式,一般为数字 protected IExpression leftExpression; //非终结表达式右边表达式,一般为数字 protected IExpression rightExpression;
public AbstractNonTerminalExpression(IExpression leftExpression, IExpression rightExpression) { this.leftExpression = leftExpression; this.rightExpression = rightExpression; }}
复制代码


  • 加法表达式类AddExpression.java


package cn.liangyy.interpreter;
/** * 非终结表达式-具体表达式-加法表达式 */public class AddExpression extends AbstractNonTerminalExpression { public AddExpression(IExpression leftExpression, IExpression rightExpression) { super(leftExpression, rightExpression); }
/** * 用来解释表达式的方法 * @return */ @Override public int interpret() { //解释器,将左右两个终结符的值相加 return this.leftExpression.interpret() + this.rightExpression.interpret(); }}
复制代码


  • 减法表达式类SubExpression.java


package cn.liangyy.interpreter;
/** * 非终结表达式-具体表达式-减法表达式 */public class SubExpression extends AbstractNonTerminalExpression { public SubExpression(IExpression leftExpression, IExpression rightExpression) { super(leftExpression, rightExpression); }
/** * 用来解释表达式的方法 * @return */ @Override public int interpret() { //解释器,将左右两个终结符的值相减 return this.leftExpression.interpret() - this.rightExpression.interpret(); }}
复制代码


  • 终结符表达式类(如加减法运算中的数值)NumberExpression.java


package cn.liangyy.interpreter;
/** * 终结表达式-数值表达式 */public class NumberExpression implements IExpression { //终结表达式的值 private int value;
public NumberExpression(String value) { this.value = Integer.valueOf(value); }
/** * 用来解释表达式的方法 * @return */ @Override public int interpret() { //解释非终结表达式 return this.value; }}
复制代码


  • 上下文信息类ExpressionContext.java


package cn.liangyy.interpreter;
import java.util.Stack;
/** * 上下文信息类 */public class ExpressionContext { //定义一个栈,计算一般都用栈,利用其先进后出的特性 private Stack<IExpression> stack = new Stack<>();
public ExpressionContext(Stack<IExpression> stack) { this.stack = stack; }
private void parse(String expression){ //为了简单,直接以空格来切割,所以测试的时候每个数字和符号之间都要有空格 String[] elementArr = expression.split(" "); for (int i = 0;i < elementArr.length;i++){ String element= elementArr[i]; if (element.equals("+")){ //加法 //站内元素出栈 IExpression leftExpression = stack.pop(); //取出+号后的下一个元素 IExpression rightExpression = new NumberExpression(elementArr[++i]); //计算 IExpression addExpression = new AddExpression(leftExpression,rightExpression); //将计算结果压入栈 stack.push(new NumberExpression(addExpression.interpret()+"")); }else if (element.equals("-")){ //减法 //栈内元素出栈 IExpression leftExpression = stack.pop(); //取出-号后的下一个元素 IExpression rightExpression = new NumberExpression(elementArr[++i]); //计算 IExpression subExpression = new SubExpression(leftExpression,rightExpression); //将计算结果压入栈 stack.push(new NumberExpression(subExpression.interpret()+"")); }else{ //如果是数字则直接入栈 stack.push(new NumberExpression(element)); } } }
/** * 运算结果 * @return */ public int calcuate(){ //经过前面解析,到这里stack内只会剩下唯一一个数字,即运算结果 return stack.pop().interpret(); }}
复制代码


  • 测试TestInterpreter.java


package cn.liangyy.interpreter;
/** * 解释器模式-测试 */public class TestInterpreter { public static void main(String[] args) { //注意每个符号之间要包含空格 ExpressionContext context = new ExpressionContext("123 + 345 + 678 - 234"); System.out.println(context.calcuate());
context = new ExpressionContext("123 - 345 + 890"); System.out.println(context.calcuate()); }}
复制代码


上述例子就是通过简单的加减法实现的一个解释器模式,这样我们对解释器模式的设计思想就有了一个很清楚的认识学习。


解释器模式适用场景


  • 当我们有一些需要重复解析的问题,可以考虑定义一个表达式来进行表达。

  • 一些简单的语法如果需要解释的话也可以考虑解释器模式。


解释器模式优点扩展性比较强。从我们上面的示例中可以看出来了,每一个表达式都是一个类,所以如果需要修改某一个规则只需要修改对应的表达式类就可以了,扩展的时候也只需要新增一个新类就可以了。


解释器模式缺点


  • 当文法规则比较复杂时,会引起类膨胀,比较难维护。

  • 当文法规则比较复杂时,如果出错了,调试比较困难。

  • 执行效率比较低下。因为当表达式比较复杂,结果层层依赖的话会采用递归方式进行解析。

发布于: 刚刚阅读数: 3
用户头像

梁歪歪 ♚

关注

时间带走了年少轻狂,无知沉淀了冷暖自知。 2021.07.22 加入

互联网行业摸爬滚打的Java后生一枚,希望在InfoQ能够充实自己的同时,结识更多大牛。

评论

发布
暂无评论
InterpreterPattern-解释器模式_设计模式_梁歪歪 ♚_InfoQ写作社区