解释器设计模式

解释器设计模式是一种行为型模式,用于构建语言解释器。它将语言的文法表示为抽象语法树,并通过解释器解释执行语言中的句子。常见使用场景包括需要解释执行的语言、简单文法的表达。模式包括抽象表达式、终端表达式和非终端表达式等角色,以实现对表达式的计算。Spring框架中的对象求值表达式也应用了此模式。
摘要由CSDN通过智能技术生成

解释器设计模式


1. 简单介绍

解释器设计模式(interpreter)是一种行为型设计模式。给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

2. 使用场景
  • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
  • 一些重复出现的问题可以用一种简单的语言来进行表达
  • 文法较为简单
3. 场景举例

编译器编辑的过程大致可以分为 词法分析、语法分析、语义分析、中间代码优化以及最终的最终代码生成。而解释器起始就是完成了语法树的解析,将一个个词组解释成一个个语法规范,交给下一个过程使用。 无论高级语言程序是怎么样编写的,编译器的代码是不用修改的,而解释器模式就是想做一个建立在Java和我们自定义语言之间的编译器。

4. UML类图

解释器模式UML类图

5. 具体实现

描述

  • 背景:给定一个包含加减的表达式如:a+b+c,分别给出abc 的值,自动计算出表达式的值
  • AbstractExpression:抽象表达式,对应AbstractExpression角色。抽象语法树节点的抽象,每个节点有自己的解释操作interpret()
  • VarExpression:变量表达式:对应TerminalExpression角色,操作数的封装对象
  • MathSymbolExpression:操作符的父类,对应NonTerminalExpression
  • PlusExpression:加法表达式:NonTerminalExpression的具体子类,将表达式左和右操作数进行+操作
  • MinusExpression:减法表达式:NonTerminalExpression的具体子类,将表达式左操作数减去右操作数
  • Calculator:将输入后的表达式每个遍历,并通过对应的Expression进行解释,提供calculate()接口,获取最终Expression的interpret()结果
  • Client:客户端,给定待计算表达式、各个变量的值

实现代码

AbstractExpression.java

/**
 * 抽象表达式,对应AbstractExpression角色
 * 抽象语法树节点的抽象,每个节点有自己的解释操作interpret()
 */
public abstract class AbstractExpression {
    public abstract int interpret(Map<String, Integer> varMap);
}

VarExpression.java

/**
 * 变量表达式:对应TerminalExpression
 * 操作数的封装对象
 */  
public class VarExpression extends AbstractExpression {

    private String key;

    public VarExpression(String key) {
        this.key = key;
    }

    @Override
    public int interpret(Map<String, Integer> varMap) {
        Integer var = varMap.get(key);
        return var == null ? 0 : var;
    }
}

MathSymbolExpression .java

/**
 * 操作符的父类,对应NonTerminalExpression
 */  
public class MathSymbolExpression extends AbstractExpression {

    /**
     * 左操作数表达式
     */
    protected AbstractExpression leftExpression;

    /**
     * 右操作数表达式
     */
    protected AbstractExpression rightExpression;

    public MathSymbolExpression(AbstractExpression leftExpression, AbstractExpression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }

    /**
     * 空实现,具体的实现,交给具体的符号表达式实现
     * @param varMap 变量Map
     * @return 表达式计算后的结果
     */
    @Override
    public int interpret(Map<String, Integer> varMap) {
        return 0;
    }
}

PlusExpression.java

/**
 * 加法表达式:NonTerminalExpression的具体子类
 * 将表达式左和右操作数进行+操作
 */  
public class PlusExpression extends MathSymbolExpression {

    public PlusExpression(AbstractExpression leftExpression, AbstractExpression rightExpression) {
        super(leftExpression, rightExpression);
    }

    @Override
    public int interpret(Map<String, Integer> var) {
        return super.leftExpression.interpret(var) + super.rightExpression.interpret(var);
    }
}

MinusExpression.java

/**
 * 减法表达式:NonTerminalExpression的具体子类
 * 将表达式左操作数减去右操作数
 */  
public class MinusExpression extends MathSymbolExpression {

    public MinusExpression(AbstractExpression leftExpression, AbstractExpression rightExpression) {
        super(leftExpression, rightExpression);
    }

    @Override
    public int interpret(Map<String, Integer> varMap) {
        return super.leftExpression.interpret(varMap) - super.rightExpression.interpret(varMap);
    }
}

Calculator.java

/**
 * 将输入后的表达式每个遍历,并通过对应的Expression进行解释
 * 提供calculate()接口,获取最终Expression的interpret()结果
 */  
public class Calculator {

    private String expStr;

    /**
     * 定义表达式
     */
    private AbstractExpression expression;

    public Calculator(String expStr) {
        this.expStr = expStr;
    }

    public void analyse() {

        Stack<AbstractExpression> expStack = new Stack<>();

        AbstractExpression left;
        AbstractExpression right;

        char[] expChar = expStr.toCharArray();
        for (int i = 0; i < expChar.length; i++) {
            char curExpChar = expChar[i];
            switch (curExpChar) {
                case '+':
                    left = expStack.pop();
                    right = new VarExpression(String.valueOf(expChar[++i]));
                    PlusExpression sumExpression = new PlusExpression(left, right);
                    expStack.push(sumExpression);
                    break;
                case '-':
                    left = expStack.pop();
                    right = new VarExpression(String.valueOf(expChar[++i]));
                    MinusExpression diffExpression = new MinusExpression(left, right);
                    expStack.push(diffExpression);
                    break;
                default:
                    expStack.push(new VarExpression(String.valueOf(curExpChar)));
                    break;
            }
        }

        this.expression = expStack.pop();
    }

    public int calculate(Map<String, Integer> varMap) {
        return this.expression.interpret(varMap);
    }
}

Client.java

/**
 * 客户端
 * 给定待计算表达式、各个变量的值
 */  
public class Client {

    public static void main(String[] args) {

        // 1. 给定待计算表达式文法
        String expStr = "a+b+c-d+e";

        // 2. 给待计算表达式文法变量输入值
        HashMap<String, Integer> varMap = new HashMap<>();
        varMap.put("a", 1);
        varMap.put("b", 2);
        varMap.put("c", 3);
        varMap.put("d", 4);
        varMap.put("e", 5);

        // 3. 文法解析
        Calculator calculator = new Calculator(expStr);
        calculator.analyse();

        // 4. 计算并打印
        System.out.println(calculator.calculate(varMap));
    }
}
7. 源码展示

Spring中的对象求值表达式ExpressionSpelExpression封装了解析算术表达式字符串的方法,该解析方法的实现采用了解释器模式。其中解释器模式中抽象表达式角色对应Spring中的Expression接口类,该类中的getValue()方法对应解释器模式中的interpret()方法。具体的Expression实现类有SpelExpressionLiteralExpressionCompositeStringExpression

Expression.java

/**
 * 抽象表达式,对应AbstractExpression角色
 * 抽象语法树节点的抽象,每个节点有自己的解释操作interpret()
 */
public interface Expression {

	/**
	 * evaluation result 解析表达的值
	 */
	@Nullable
	Object getValue() throws EvaluationException;
}

SpelExpression.java

public class SpelExpression implements Expression {

	/**
	 * 对Spel这种特定的表达式进行解释计算
	 */
	@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;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值