行为类模式(三):解释器(Interpreter)

时间:2023-12-09 22:51:31

定义

给定一个语言, 定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

UML

行为类模式(三):解释器(Interpreter)

优点

  1. 将每一个语法规则表示成一个类,方便事先语言。
  2. 因为语法由许多类表示,所以你可以轻易地改变或扩展此语言
  3. 通过在类结构中加入新的方法,可以在解释的同时增加新的行为,例如打印格式的梅花或者进行复制的程序验证。

缺点

  1. 解释器模式会引起类膨胀,每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。
  2. 解释器模式采用递归调用方法,每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下使用的,它导致调试非常复杂。想想看,如果要排查一个语法错误,我们是不是要一个一个断点的调试下去,直到最小的语法单元。
  3. 效率问题,解释器模式由于使用了大量的循环和递归,效率是个不容忽视的问题,特别是用于解析复杂、冗长的语法时,效率是难以忍受的。

应用场景

  1. 重复发生的问题可以使用解释器模式。
  2. 一个简单语法需要解释的场景。
  3. 可以处理脚本语言和编程语言,比如正则表达式。

示例

使用解释器模式完成一个两则运算器,要求输入表达式和每个符号的值得到表达式的最终结果。

Java

 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Stack; public class Main
{
public static void main(String[] args) throws IOException
{
String expStr = getExpStr();
//赋值
HashMap<String, Integer> var = getValue(expStr);
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 exprStr) throws IOException
{
HashMap<String, Integer> map = new HashMap<>();
//解析有几个参数要传递
for (char ch : exprStr.toCharArray())
{
if (ch != '+' && ch != '-')
{
//解决重复参数的问题
if (!map.containsKey(String.valueOf(ch)))
{
System.out.print("请输入" + ch + "的值:");
String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
map.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return map;
} /**
* 表达式基类
*/
public static abstract class Expression
{
/**
* 解析公式和数值
* @param var key值是是公式中的参数,value值是具体的数字
* @return 结果
*/
public abstract int interpreter(HashMap<String, Integer> var);
} /**
* 取值表达式
*/
public static class VarExpression extends Expression
{
private String key; public VarExpression(String _key)
{
key = _key;
} @Override
public int interpreter(HashMap<String, Integer> var)
{
return var.get(key);
}
} /**
* 运算表达式,仅关心左右两个值
*/
public static abstract class SymbolExpression extends Expression
{
protected Expression left;
protected Expression right; public SymbolExpression(Expression _left, Expression _right)
{
this.left = _left;
this.right = _right;
}
} /**
* 加法表达式处理
*/
public static class AddExpression extends SymbolExpression
{
public AddExpression(Expression _left, Expression _right)
{
super(_left, _right);
} public int interpreter(HashMap<String, Integer> var)
{
return super.left.interpreter(var) + super.right.interpreter(var);
}
} /**
* 减法表达式处理
*/
public static class SubExpression extends SymbolExpression
{
public SubExpression(Expression _left, Expression _right)
{
super(_left, _right);
} public int interpreter(HashMap<String, Integer> var)
{
return super.left.interpreter(var) - super.right.interpreter(var);
}
} /**
* 运算类
*/
public static class Calculator
{
//定义的表达式
private Expression expression; //构造函数传参,并解析
public Calculator(String expStr)
{
//定义一个堆栈,安排运算的先后顺序
Stack<Expression> stack = new Stack<Expression>();
//表达式拆分为字符数组
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])));
}
}
//把运算结果抛出来
this.expression = stack.pop();
} //开始运算
public int run(HashMap<String, Integer> var)
{
return this.expression.interpreter(var);
}
}
}