1. 解释器模式概念
计算机用来解释句子或表达式,类似在软件开发过程中,有时需要处理一系列多次重复出现的问题。如果将这类问题归纳成一种简单的语言,那么这些问题实例将是该语言的一些句子,这样就可以用编译原理中的解释器模式来实现了。
解释器模式的定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解释器来解释语言中的句子,即用编译语言的方式来分析应用中的实例。
解释器模式优点:
- 扩展性好,由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
- 容易实现,在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。
解释器模式缺点:
- 执行效率较低,解释器模式中通常使用大量的循环和递归调用,当要解释的句子比较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
- 会引起类膨胀,解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
- 可应用的场景比较少,在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。
解释器模式类图如下:
- 环境(Context):用于封装解释器的全局信息,主要任务是将需要分析的句子或表达式转化成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法。
- 抽象表达式(AbstractExpression):定义解释器的接口,约定解释器的解释操作。
- 终结符表达式(TerminalExpression):抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之对应。
- 非终结符表达式(NonterminalExpression):抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应一个非终结符表达式。
2. 解释器模式案例
使用解释器的方式实现加减运算,例如输入表达式a+b+c-d,a=10,b=50,c=20,d=10,输出计算结果。
2.1 抽象表达式
新建抽象表达式接口,约定解释器的解释操作,接口名称为Expression,内容如下:
public interface Expression {
Integer interpret(Map<String, Integer> map);
}
2.2 终结符表达式
在加减运算中,变量不可以继续进行推演运算属于终结符,新建变量表达式类,解释操作返回自身的值,类名为VariableExpression,内容如下:
public class VariableExpression implements Expression {
private String variableKey;
public VariableExpression(String variableKey){
this.variableKey = variableKey;
}
@Override
public Integer interpret(Map<String, Integer> map) {
return map.get(variableKey);
}
}
2.3 非终结符表达式
在加减运算中,运算符号“+”与“-”可以继续推导属于非终结符,新建非终结符表达式基类,定义左右两个表达式属性,类名为SymbolExpression,内容如下:
public class SymbolExpression implements Expression{
protected Expression leftExpression;
protected Expression rightExpression;
public SymbolExpression(Expression leftExpression, Expression rightExpression){
this.leftExpression = leftExpression;
this.rightExpression = rightExpression;
}
@Override
public Integer interpret(Map<String, Integer> map) {
return 0;
}
}
新建加法非终结符表达式类用来解释加法,类名为AddSymbolExpression,内容如下:
public class AddSymbolExpression extends SymbolExpression{
public AddSymbolExpression(Expression leftExpression, Expression rightExpression) {
super(leftExpression, rightExpression);
}
@Override
public Integer interpret(Map<String, Integer> map) {
return leftExpression.interpret(map) + rightExpression.interpret(map);
}
}
类似新建减法终结符表达式类用来解释减法,类名为SubSymbolExpression,内容如下:
public class SubSymbolExpression extends SymbolExpression {
public SubSymbolExpression(Expression leftExpression, Expression rightExpression) {
super(leftExpression, rightExpression);
}
@Override
public Integer interpret(Map<String, Integer> map) {
return leftExpression.interpret(map) - rightExpression.interpret(map);
}
}
2.4 环境
新建环境类用来执行解析表达式,类名为Calculator,内容如下:
public class Calculator {
private Expression expression;
public Calculator(String expression) {
char[] charArray = expression.toCharArray();
Stack<Expression> stack = new Stack();
Expression left;
Expression right;
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]){
case '+':
left = stack.pop();
right = new VariableExpression(String.valueOf(charArray[++i]));
stack.push(new AddSymbolExpression(left, right));
break;
case '-':
left = stack.pop();
right = new VariableExpression(String.valueOf(charArray[++i]));
stack.push(new SubSymbolExpression(left, right));
break;
default:
stack.push(new VariableExpression(String.valueOf(charArray[i])));
break;
}
}
this.expression = stack.pop();
}
public Integer calculate(Map<String, Integer> map){
return expression.interpret(map);
}
}
2.5 客户端
新建客户端测试,内容如下:
public class Client {
public static void main(String[] args) {
String expression = "a+b+c-d";
Map<String, Integer> map = new HashMap(){{
put("a", 10);
put("b", 50);
put("c", 20);
put("d", 10);
}};
Calculator calculator = new Calculator(expression);
Integer result = calculator.calculate(map);
System.out.println("result = " + result);
}
}
3. 解释器模式应用
解释器模式适用于表达式被解释并转换为其内部表示的情况。在JAVA的Pattern中实现了解释器模式,它用于解析正则表达式。在解释正则表达式时返回匹配器对象,匹配器使用基于正则表达式的模式类创建的内部结构,使用如下:
public class Test {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("a*b");
Matcher matcher = pattern.matcher("aaaaaaab");
boolean result = matcher.matches();
System.out.println("result = " + result);
}
}
|