解释器模式( Interpreter Pattern)是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子.是一种按照规定的语法(文法)进行解析的模式,属于行为型模式。
就比如编译器可以将源码编译解释为机器码,让CPU能进行识别并运行。解释器模式的作用其实与编译器一样,都是将一些固定的文法(即语法)进行解释,构建出一个解释句子的解释器。简单理解,解释器是一个简单语法分析工具,它可以识别句子语义,分离终结符号和非终结符号,提取出需要的信息,让我们能针对不同的信息做出相应的处理。其核心思想是识别文法,构建解释。
以下代码以运算符解析为例:
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description: 数学计算解析器接口
* @author: liu wei ping
* @create: 2022-05-15 10:32
*/
public interface IArithmeticInterpreter {
int interpret();
}
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description: 解释器模式
* @author: liu wei ping
* @create: 2022-05-15 10:32
*/
public abstract class Interpreter implements IArithmeticInterpreter{
protected IArithmeticInterpreter left;
protected IArithmeticInterpreter right;
public Interpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
this.left = left;
this.right = right;
}
}
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description: 加计算
* @author: liu wei ping
* @create: 2022-05-15 10:31
*/
public class AddInterpreter extends Interpreter{
public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() + this.right.interpret();
}
}
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description: 相减运算
* @author: liu wei ping
* @create: 2022-05-15 10:34
*/
public class SubInterpreter extends Interpreter{
public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() - this.right.interpret();
}
}
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description: 乘计算
* @author: liu wei ping
* @create: 2022-05-15 10:33
*/
public class MultiInterpreter extends Interpreter{
public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() * this.right.interpret();
}
}
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description: 相除计算
* @author: liu wei ping
* @create: 2022-05-15 10:31
*/
public class DivInterpreter extends Interpreter{
public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() / this.right.interpret();
}
}
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description: 运算工具类
* @author: liu wei ping
* @create: 2022-05-15 10:33
*/
public class OperatorUtil {
/**
* 判断是否是运算符
* @param symbol
* @return
*/
public static boolean isOperator(String symbol) {
return (symbol.equals("+") || symbol.equals("-") ||symbol.equals("*")
|| symbol.equals("/"));
}
/**
* 根据运算符运算值
* @param left
* @param right
* @param symbol
* @return
*/
public static Interpreter getInterpreter(IArithmeticInterpreter left,IArithmeticInterpreter right,String symbol) {
if (symbol.equals("+")) {
return new AddInterpreter(left,right);
} else if(symbol.equals("-")) {
return new SubInterpreter(left,right);
} else if(symbol.equals("*")) {
return new MultiInterpreter(left,right);
} else if(symbol.equals("/")) {
return new DivInterpreter(left,right);
}
return null;
}
}
package com.lx.designPattern.interpreterpattern.calculate;
import java.util.Stack;
/**
* @program: People
* @description: 运算符计算类
* @author: liu wei ping
* @create: 2022-05-15 10:31
*/
public class GPCalculator {
private Stack<IArithmeticInterpreter> stack =new Stack<IArithmeticInterpreter>();
public GPCalculator (String expression) {
this.parse(expression);
}
/**
* 解析运算符
* @param expression
*/
private void parse(String expression) {
String[] elements = expression.split(" ");
IArithmeticInterpreter leftExpr, rightExpr;
for (int i=0; i<elements.length ; i++) {
String operator = elements[i];
if (OperatorUtil.isOperator(operator)) {
leftExpr = this.stack.pop();
rightExpr = new NumInterpreter(Integer.valueOf(elements[++i]));
System.out.println("出栈:" + leftExpr.interpret() + "和" + rightExpr.interpret());
this.stack.push(OperatorUtil.getInterpreter(leftExpr,rightExpr,operator));
System.out.println("应用运算符:" + operator);
}
else {
NumInterpreter numInterpreter = new NumInterpreter(Integer.valueOf(elements[i]));
this.stack.push(numInterpreter);
System.out.println("入栈:" + numInterpreter.interpret());
}
}
}
public int calculate() {
return this.stack.pop().interpret();
}
}
package com.lx.designPattern.interpreterpattern.calculate;
/**
* @program: People
* @description:
* @author: liu wei ping
* @create: 2022-05-15 10:34
*/
public class Test {
public static void main(String[] args) {
System.out.println("result:" + new GPCalculator("10 + 30").calculate());
System.out.println("result:" + new GPCalculator("10 + 30 - 20").calculate());
System.out.println("result:" + new GPCalculator("100 * 2 + 400 * 1 + 66").calculate());
}
}
运行结果如下图:
Spring的解释器模式:
package com.lx.designPattern.interpreterpattern.calculate;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* @program: People
* @description: Spring 的解释器模式,解析表达式
* @author: liu wei ping
* @create: 2022-05-15 10:33
*/
public class SpringTest {
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("100 * 2 + 400 * 1 +66");
int result = (Integer) expression.getValue();
System.out.println("计算结果是:" + result);
}
}
测试结果如下图:结果一样
解释器模式的优缺点优点:
1、扩展性强:在解释器模式中由于语法是由很多类表示的,当语法规则更改时,只需修改相应的非终结符表达式即可;若扩展语法时,只需添加相应非终结符类即可;
2、增加了新的解释表达式的方式;
3、易于实现文法:解释器模式对应的文法应当是比较简单且易于实现的,过于复杂的语法并不适合使用解释器模式。
缺点:
1、语法规则较复杂时,会引起类膨胀:解释器模式每个语法都要产生一个非终结符表达式当语法规则比较复杂时,就会产生大量的解释类,增加系统维护困难;
2、执行效率比较低:解释器模式采用递归调用方法,每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,因此完整表达式的最终结果是通过从后往前递归调用的方式获取得到。当完整表达式层级较深时,解释效率下降,且出错时调试困难,因为递归迭代层级太深。