这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战
解释器模式
给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。
也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
结构
抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器NonterminalExpression完成
终结符表达式(Terminal Expression)角色:用来实现文法中与终结符相关的操作,通常一个解释器模式中只有一个终结符表达式,如果公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
非终结符表达式(Nonterminal Expression)角色:用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。
环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
演示
1、抽象表达式
public interface Expression {
public int interpret(HashMap<String, Integer> var);
}
2、终结者表达式
public class TerminalExpression implements Expression {
private String key;
public TerminalExpression(String key) {
this.key = key;
}
@Override
public int interpret(HashMap<String, Integer> var) {
return var.get(this.key);
}
}
3、非终结者表达式
public class NonterminalExpression implements Expression {
protected Expression left;
protected Expression right;
public NonterminalExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(HashMap<String, Integer> var) {
return 0;
}
}
public class AddExpression extends NonterminalExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
public int interpret(HashMap<String, Integer> var) {
return left.interpret(var) + right.interpret(var);
}
}
4、环境角色
public class Calculator {
private Expression expression;
public Calculator(String exception) {
// 安排运算先后顺序
Stack<Expression> stack = new Stack<>();
// 表达式拆分为字符数组
char[] charArray = exception.toCharArray();
Expression left = null;
Expression right = null;
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case '+': // 加法
left = stack.pop();
right = new TerminalExpression(String.valueOf(charArray[++i]));
stack.push(new AddExpression(left, right));
break;
case '-': // 减法
left = stack.pop();
right = new TerminalExpression(String.valueOf(charArray[++i]));
stack.push(new NonterminalExpression(left, right));
break;
default: // 公式中的变量
stack.push(new TerminalExpression(String.valueOf(charArray[i])));
break;
}
}
this.expression = stack.pop();
}
// 计算
public int run(HashMap<String, Integer> var) {
return this.expression.interpret(var);
}
}
5、客户端
public class Client {
public static void main(String[] args) throws IOException {
String expStr = "a+b";
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 314325);
map.put("b", 143987);
Calculator calculator = new Calculator(expStr);
System.out.println("结果:" + expStr + "=" + calculator.run(map));
// 结果:a+b=458312
}
}
总结
上面的代码通过实现一个计算机加法demo展示,可以看到 1、解释器模式的扩展性是很好的,语法规则的变化只需要操作非终结者表达式就可以;同时增加一项语法就需要新增一个非终结者表达式类;如果语法复杂,会导致系统类膨胀。
2、使用了循环,解析一个复杂的语句时效率会比较慢
3、目前实现场景比较少,就算遇到也可以通过其他方式替代,如:Java中的expression4J