文章目录
- 解释器模式
- 1.解释器模式的本质
- 2.何时选用解释器模式
- 3.优缺点
- 4.解释器模式的结构
- 5.实现
- 计算器加减操作
解释器模式
当想解析一个文件或者其他内容时,可以根据规律自己定义一种文法,并定义一个解释器,然后解析这种文法,以达到解析文件或其他内容的效果
1.解释器模式的本质
解释器模式的本质:分离实现,解释执行。
解释器模式通过一个解释器对象处理一个语法规则的方式,把复杂的功能分离开;然后选择需要被执行的功能,并把这些功能组合成为需要被解释执行的抽象语法树;再按照抽象语法树来解释执行,实现相应的功能。
2.何时选用解释器模式
建议在以下情况中选用解释器模式。
当有一个语言需要解释执行,并且可以将该语言中的句子表示为一个抽象语法树的时候,可以考虑使用解释器模式。
在使用解释器模式的时候,还有两个特点需要考虑,一个是语法相对应该比较简单,太复杂的语法不适合使用解释器模式;另一个是效率要求不是很高,对效率要求很高的情况下,不适合使用解释器模式。
3.优缺点
解释器模式有以下优点。.
-
易于实现语法
在解释器模式中,一条语法规则用一个解释器对象来解释执行。对于解释器的实现来讲,功能就变得比较简单,只需要考虑这一条语法规则的实现就可以了,其他的都不用管。 -
易于扩展新的语法
正是由于采用一个解释器对象负责一条语法规则的方式,使得扩展新的语法非常容易。扩展了新的语法,只需要创建相应的解释器对象,在创建抽象语法树的时候使用这个新的解释器对象就可以了。
解释器模式的缺点是不适合复杂的语法。
如果语法特别复杂,构建解释器模式需要的抽象语法树的工作是非常艰巨的,再加上有可能会需要构建多个抽象语法树。所以解释器模式不太适合于复杂的语法,对于复杂的语法,使用语法分析程序或编译器生成器可能会更好一些。
4.解释器模式的结构
- AbstractExpression:定义解释器的接口,约定解释器的解释操作。
- TerminalExpression:终结符解释器,用来实现语法规则中和终结符相关的操作,不再包含其他的解释器,如果用组合模式来构建抽象语法树的话,就相当于组合模式中的叶子对象,可以有多种终结符解释器。
- NonterminalExpression:非终结符解释器,用来实现语法规则中非终结符相关的操作,通常一个解释器对应一个语法规则,可以包含其他的解释器,如果用组合模式来构建抽象语法树的话,就相当于组合模式中的组合对象。可以有多种非终结符解释器。
- Context:上下文,通常包含各个解释器需要的数据或是公共的功能。
- Client:客户端,指的是使用解释器的客户端,通常在这里将按照语言的语法做的表达式转换成为使用解释器对象描述的抽象语法树,然后调用解释操作。
5.实现
解释器模式的核心思想是:定义一种文法,并定义一个解释器,使用该解释器来解释这个文法。
文法:可以将其理解为一种规则,就好比汉语中一句话必须由“主谓宾”三者构成一样。下面的文法是加减操作,只要是加减操作下面的解释器就可以进行解析。
计算器加减操作
实现一个计算器的加减操作
1.解释器接口及其实现类
/**
* @description:解释器接口
*/
public interface Expression {
/**
* 解析表达式
* @return
*/
int interpret();
}
/**
* @description:数值解释器
*/
public class NumExpression implements Expression {
private int value;
public NumExpression(int value) {
this.value = value;
}
@Override
public int interpret() {
return this.value;
}
}
/**
* @description:加法解释器
*/
public class AddExpression implements Expression {
public Expression left;
public Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return this.left.interpret() + this.right.interpret();
}
}
/**
* @description:减法解释器
*/
public class SubExpression implements Expression {
public Expression left;
public Expression right;
public SubExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return this.left.interpret() - this.right.interpret();
}
}
2.上下文类
/**
* @description:计算器类(上下文)
*/
public class Calculator {
//栈
private Stack<Expression> stack = new Stack<>();
/**
* @author conggq
* @description:解释文法方法
* @createTime 2022/11/30 13:06
*/
public int parse(String expression) {
String[] elements = expression.split(" ");
Expression leftExpr, rightExpr;
for (int i = 0; i < elements.length; i++) {
String operator = elements[i];
if (("+".equals(operator) || "-".equals(operator))) {
leftExpr = this.stack.pop();
rightExpr = new NumExpression(Integer.valueOf(elements[++i]));
if ("+".equals(operator)) {
this.stack.push(new AddExpression(leftExpr, rightExpr));
} else if ("-".equals(operator)) {
this.stack.push(new SubExpression(leftExpr, rightExpr));
}
} else {
NumExpression numInterpreter = new NumExpression(Integer.valueOf(elements[i]));
this.stack.push(numInterpreter);
}
}
//等价于new SubExpression(new AddExpression(new NumExpression(10), new NumExpression(30)), new NumExpression(20)).interpret()
return this.stack.pop().interpret();
}
}
3.测试类
/**
* @description:测试类
*/
public class Client {
public static void main(String[] args) {
System.out.println("result: " + new Calculator().parse("10 + 30 - 20"));
System.out.println("result: " + new SubExpression(new AddExpression(new NumExpression(10), new NumExpression(30)), new NumExpression(20)).interpret());
}
}
4.结果