设计模式--解释器模式

案例

计算a+b-c的值,先输入表达式的形式,比如a+b-c,要求表达式的字母不能重复,再分别输入a,b,c的值,最后求出结果。

传统方案

编写一个计算方法,接收表达式的形式,然后根据用户输入的数值进行解析得到结果(将所有的计算细节放在一个方法里)

传统方案带来的问题

如果加入新的运算符,比如*/等等,需要对计算方法进行修改,违背了开闭原则,不利于扩展;另外将所有的计算细节都放到一个方法里会使得该方法非常臃肿,程序结构混乱,程序难以维护

使用解释器模式

解决方案:表达式->解释器(可以有多种)->结果
几个重要的角色:Expression抽象表达式类,声明了一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享;VarExpression终结符表达式类,实现与文法中的终结符相关的解释操作;SymbolExpression非终结符表达式类,为文法中的非终结符实现解释操作。AddExpression实现对加的解释操作,SubExpression实现对减的解释操作
解释器模式

/**
 * 
 * @ClassName InterpreterPattern
 * @Description 解释器模式
 * @author fuling
 * @date 2020年11月3日 下午9:11:20
 */
public class InterpreterPattern {
	public static void main(String[] args) {
		String exp = "a+b-c";
		Map<String, Integer> var = new HashMap<>();
		var.put("a", 1);
		var.put("b", 4);
		var.put("c", 2);
		Calculator calculator = new Calculator(exp);
		System.out.println(calculator.run(var));
	}
	
}

class Calculator{
	Expression expression;
	
	Calculator(String exp){
		
		Stack<Expression> stack = new Stack();
		char[] charArray = exp.toCharArray();
		Expression left;
		Expression right;
		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();
	}
	
	int run(Map<String, Integer> var) {
		return this.expression.interpreter(var);
	}
}

/**
 * 
 * @ClassName Expression
 * @Description 抽象表达式类
 * @author fuling
 * @date 2020年11月3日 下午9:17:56
 */
abstract class Expression{
	/**
	 * 
	 * @Title interpreter
	 * @Description 描述这个方法的作用
	 * @param @param var 存放终结符和数值的映射,比如{a=>1,b=>3}
	 * @param @return 参数说明
	 * @return 返回解释器解析后的结果
	 * @throws
	 */
	abstract int interpreter(Map<String, Integer> var);
}

/**
 * 
 * @ClassName VarExpression
 * @Description 终结符表达式
 * @author fuling
 * @date 2020年11月3日 下午9:27:15
 */
class VarExpression extends Expression{
	String key;

	VarExpression(String key){
		this.key = key;
	}
	
	/**
	 * 
	 * @Title interpreter
	 * @Description 终结符的解释方法:从键值对映射中取出值
	 * @param @param var
	 * @param @return
	 * @see Expression#interpreter(java.util.Map)
	 */
	@Override
	int interpreter(Map<String, Integer> var) {
		return var.get(key);
	}
	
}

/**
 * 
 * @ClassName SymbolExpression
 * @Description 非终结符表达式
 * @author fuling
 * @date 2020年11月3日 下午9:30:18
 */
abstract class SymbolExpression extends Expression{
	
	Expression left;//左操作表达式
	Expression right;//右操作表达式
	
	SymbolExpression(Expression left, Expression right){
		this.left = left;
		this.right = right;
	}

	@Override
	abstract int interpreter(Map<String, Integer> var);
	
}

/**
 * 
 * @ClassName SubExpression
 * @Description “减”表达式
 * @author fuling
 * @date 2020年11月3日 下午9:30:33
 */
class SubExpression extends SymbolExpression{

	SubExpression(Expression left, Expression right) {
		super(left, right);
	}

	
	/**
	 * 
	 * @Title interpreter
	 * @Description 非终结符的解释方法:对两边的操作表达式执行减的操作
	 * @param @param var
	 * @param @return
	 * @see SymbolExpression#interpreter(java.util.Map)
	 */
	@Override
	int interpreter(Map<String, Integer> var) {
		return this.left.interpreter(var) - this.right.interpreter(var);
	}
	
}


/**
 * 
 * @ClassName AddExpression
 * @Description “加”表达式
 * @author fuling
 * @date 2020年11月3日 下午9:30:58
 */
class AddExpression extends SymbolExpression{

	AddExpression(Expression left, Expression right) {
		super(left, right);
	}

	/**
	 * 
	 * @Title interpreter
	 * @Description 非终结符的解释方法:对两边的操作表达式执行加的操作
	 * @param @param var
	 * @param @return
	 * @see SymbolExpression#interpreter(java.util.Map)
	 */
	@Override
	int interpreter(Map<String, Integer> var) {
		return this.left.interpreter(var) + this.right.interpreter(var);
	}
	
}

使用了解释器模式后,程序具有更好的扩展性,当需求增加一种新的运算符时,只需要添加一个新解释器即可

解释器模式小结
  1. 解释器模式,是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
  2. 当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程序具有更好的扩展性
  3. 使用解释器模式可能带来的问题:引起类膨胀;由于解释器模式采用递归调用方法,这将会导致调试非常复杂,效率可能降低
  4. 应用场景:编译器,运算表达式计算,正则表达式,机器人等
解释器模式在spring框架中的使用

SpelExpressionParser使用到了解释器模式,该类实现了ExpressionParser接口

public interface ExpressionParser {

	/**
	 * Parse the expression string and return an Expression object you can use for repeated evaluation.
	 * <p>Some examples:
	 * <pre class="code">
	 *     3 + 4
	 *     name.firstName
	 * </pre>
	 * @param expressionString the raw expression string to parse
	 * @return an evaluator for the parsed expression
	 * @throws ParseException an exception occurred during parsing
	 */
	Expression parseExpression(String expressionString) throws ParseException;

	/**
	 * Parse the expression string and return an Expression object you can use for repeated evaluation.
	 * <p>Some examples:
	 * <pre class="code">
	 *     3 + 4
	 *     name.firstName
	 * </pre>
	 * @param expressionString the raw expression string to parse
	 * @param context a context for influencing this expression parsing routine (optional)
	 * @return an evaluator for the parsed expression
	 * @throws ParseException an exception occurred during parsing
	 */
	Expression parseExpression(String expressionString, ParserContext context) throws ParseException;

}

该接口的parseExpression方法可以返回Expression实例,也就是说不同的ExpressionParser 实现类返回不同的Expression
Expression
ExpressionParser

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值