解释器模式介绍
解释器模式是一种用得比较少的行为模式,其提供了一种解释语言的语法或表达式,该模式定义了一个表达式接口,通过该接口解释一个特定的上下文。
解释器模式的定义
给定一个语言,定义它的文法的,并定义它的解释器,该解释器用来解释该文法的一个表示语言中的句子。这就是解释器模式,定义比较抽象,如四则运算,表达式a+b+c-d,通过解释器模式,解释表达式实现加减运算。这个表达式可以为任何遵循相同文法的表达式,如a+b,a-c,d-w等等。
解释器模式的使用场景
解释器模式的使用场景相当广泛,如四则运算,文字转换等,
加减法运算解释器模式UML类图
抽象表示类
public abstract class Expression {
//key是参数,value是具体的数值
public abstract int interpreter(HashMap<String, Integer> var);
}
变量解析器
public class VarExpression extends Expression{
private String key;
public VarExpression(String _key) {
this.key = _key;
}
//从map中取值
@Override
public int interpreter(HashMap<String, Integer> var) {
return var.get(this.key);//得到参数的值
}
}
这个类解析很有意思,
抽象运算符号解析器
public abstract class SymbolExpression extends Expression{
protected Expression left;
protected Expression right;
public SymbolExpression(Expression _left,Expression _right) {
this.left = _left;
this.right = _right;
}
}
每个运算符号都只和自己左右两个数字有关系,左右两个数字有可能也是一个解析结果,无论何种,结果都是Expression的实现类,于是在对运算符解析的子类中增加一个构造函数,传递左右两个表达式。具体的加,减法解析器如下所示:
加法解析器
public class AddExpression extends SymbolExpression {
public AddExpression(Expression _left, Expression _right) {
super(_left, _right);
}
//加法运算
@Override
public int interpreter(HashMap<String, Integer> var) {
return left.interpreter(var) + right.interpreter(var);
}
}
减法解析器
public class SubExpression extends SymbolExpression {
public SubExpression(Expression _left, Expression _right) {
super(_left, _right);
}
//减法运算
@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var)-super.right.interpreter(var);
}
}
加,减法类解析,里面的interpreter方法,最后是通过VarExpression的interpreter方法获取map集合里面参数的数值做加减法运算,返回运算结果。上面解析器的开发已经完成了,但需求还没有实现,需要对解析器封装,封装的类Calculator如下:
public 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]) {
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:
stack.push(new VarExpression(String.valueOf(charArray[i])));//公式中的变量
break;
}
}
this.expression = stack.pop();
}
public int run(HashMap<String, Integer> var){
return this.expression.interpreter(var);
}
}
Calculator构造函数接收一个表达式,然后把表达式转化为char数组,并判断运算符‘+’,‘-’。逐个循环字符数组,把参数压入栈,如果是运算符就出栈和下一个字符进行运算,再压入栈,后面都是同理。压如栈里面的都是VarExpression对象。这个对象实现的interpreter方法是返回map集合里面参数的数值,最后在AddExpression和SubExpression类的interpreter方法里面实现加发计算返回结果。
最后是客户端实现根据需求是客户能够修改表达式,所以通过客户端输入实现计算,代码如下:
public static void main(String[] args) {
String expStr = null;
HashMap<String, Integer> var = null;
try {
expStr = getExpStr();
var = getValue(expStr);
} catch (IOException e) {
e.printStackTrace();
}
Calculator cal = new Calculator(expStr);
System.out.println("运算结果为:" + expStr + "=" + cal.run(var));
}
public static String getExpStr() throws IOException{
System.out.print("请输入表达式:");
return (new BufferedReader(new InputStreamReader(System.in))).readLine();
}
public static HashMap<String, Integer> getValue(String expStr) throws IOException{
HashMap<String, Integer> map = new HashMap<String,Integer>();
for(char ch:expStr.toCharArray()){
if (ch != '+' && ch != '-') {
//重复的参数判断
if (!map.containsKey(String.valueOf(ch))) {
System.out.println("请输入" + ch + "的值:");
String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
map.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return map;
}
执行结果
请输入表达式:a+b-s
请输入a的值:
10
请输入b的值:
20
请输入s的值:
15
运算结果为:a+b-s=15
这样就实现了加,减法运算,如果需要扩展添加乘除法运算,只要添加继承SymbolExpression类的乘除法类,再在Calculator类里面实现‘*’‘/’运算符号,并且要考虑表达式运算符的优先级。
最后来说一下解释器模式的优缺点:
优点:解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只有修改相应的非终结符表达式就可以了,若扩展语法,则只要增加非终结符类就可以了。
缺点:每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。