解释器模式概述
什么是解释器: 定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子,简单来说,就是为了解释一种语言,为这个语言创建的解释器,例如java语言,C语言,各种语言都有对应的编译器进行编译,这个编译器就相当于解释器
解释器模角色分析
- 抽象表达式 AbstractExpression:定义解释器的接口,约定解释器的解释操作,主要包含解释方法。
- 终结符表达式 TerminalExpression:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式 NonterminalExpression:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境 Context:通常包含各个解释器需要的数据或是公共的功能,持有解释器对象, 后面的解释器可以从这里获取这些值。
解释器模式案例
案例
设计一个可以加减的计算器
- 创建抽象表达式
//抽象表达式,通过HashMap的键值对可以获取到变量的值
abstract class Expression{
//解释公式与数值的关系,key就是公式参数例如(a+b-c),key就是里面的abc
//value就是具体的值
public abstract int interpreter(HashMap<String,Integer> var);
}
- 创建变量解析器,继承抽象表达式
//变量解析器
class VarExpression extends Expression{
private String key; //key=a,key=b,key=c
public VarExpression(String key) {
this.key = key;
}
//根据变量的名称返回对应的值
@Override
public int interpreter(HashMap<String, Integer> var) {
return var.get(this.key );
}
}
- 创建抽象符号解析器,此处也充当了默认没有符号的解释器(是否是必须要的?是否必须继承Expression)
//抽象符号解析器
class SymbolExpression extends Expression{
//符号左右两个的数据,符号左右两个可能还是一个具体的表达式
//所以使用 Expression 类型
public Expression left;
public Expression right;
public SymbolExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
//抽象符号解析器中提供默认实现(根据需求在子类中进行具体实现
@Override
public int interpreter(HashMap<String, Integer> var) {
return 0;
}
}
- 创建"+"符号解析器,继承抽象符号解释器
//加法符号解析器
class AddExpression extends SymbolExpression{
public AddExpression(Expression left, Expression right) {
super(left, right);
}
public int interpreter(HashMap<String, Integer> var) {
//返回left表达式对应的值 + 返回right表达式对应的值
return super.left.interpreter(var) + super.right.interpreter(var);
}
}
- 创建"-"符号解析器,继承抽象符号解释器
//减法符号解析器 非终结符表达式
class SubExpression extends SymbolExpression{
public SubExpression(Expression left, Expression right) {
super(left, right);
}
public int interpreter(HashMap<String, Integer> var) {
//返回left表达式对应的值 - 返回right表达式对应的值
return super.left.interpreter(var) - super.right.interpreter(var);
}
}
- 创建上下文
class Calculator{
private Expression expression;
public Calculator(String expStr) {
//安排运算的先后顺序
Stack<Expression> stack = new Stack<>();
//将运算符号转换为字符数组
char[] charArray = expStr.toCharArray();
Expression left = null;
Expression right = null;
for(int i =0; i< charArray.length; i++) {
switch(charArray[i]) {
//一个运算表达式'a+b'如果转换为数组变成了[a,+,b]
//遍历出'+',可以判断'+'下标的前一个元素与后一个元素
//都是运算数据的变量名,在遍历时如果是变量名,会存入Stack
//取出stack中最后添加的数据,也就是"+"的上一个元素
//然后'+'的下标+1获取下一个变量元素,初始化AddExpression
//对象存入stack中
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:
//如果遍历charArray得到的是英文字符,说明是符号两边的变量数据
//获取变量数据,push到stack中
stack.push(new VarExpression(String.valueOf(charArray[i])));
break;
}
}
//当整个charArray数组遍历完毕后,整个运算公式也就组合完毕了,
//并且全都存入了stack中,在stack中弹出
this.expression = stack.pop();
}
public int run(HashMap<String, Integer> var) {
//解析表达式
return this.expression.interpreter(var);
}
}
- 调用测试
public static void main(String[]args) {
Calculator calculator = new Calculator("a+b-c");
HashMap<String,Integer> map = new HashMap<>();
map.put("a", 10);
map.put("b", 20);
map.put("c", 1);
System.out.println(calculator.run(map));
}
使用不是太多,并且没太明白怎么区分终结符与非终结符,不是太明白,只是简单记录