设计模式之解释器模式
设计模式之解释器模式
解释器模式:是一种按照规定语法进行解析的方案,在现在项目中使用较少 ,给定一门语言,定义它的规则的一种表达式,并定义一个解释器,该解释器使用该表达式来解释语言中的句子。
用的比较少,了解即可
2.解释器模式例子:
例子:输入一个模型公式(加、减运算),然后输入模型中的参数,运算出结果。

3.代码
3.1 创建一个Expression表达式类
public abstract class Expression {
/**
* 抽象表达式,用来解析表达式的值
* map的key表示具体的变量。value表示变量的值
*
* @param map
* @return
*/
public abstract int interpreter(Map<String, Integer> map);
}
3.2 创建一个变量解析器
public class VarExpression extends Expression {
private String key;
public VarExpression(String key) {
this.key = key;
}
// 获取具体变量的值
@Override
public int interpreter(Map<String, Integer> map) {
return map.get(key);
}
}
3.3 抽象运算符号解析器
public abstract class SymbolExpression extends Expression {
protected Expression left;
protected Expression right;
public SymbolExpression(Expression left, Expression right) {
System.out.println("调用了symbolExpression中的方法=========>left " + left + "=========>" + "right: " + right + " ");
this.left = left;
this.right = right;
}
}
3.4 加法解析器
public class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(Map<String, Integer> map) {
int result = super.left.interpreter(map) + super.right.interpreter(map);
System.out.println(" add中的result============>" + result + " ");
return result;
}
}
3.5 减法解析器
public class SubExpression extends SymbolExpression {
public SubExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(Map<String, Integer> map) {
int subresult = super.left.interpreter(map) - super.right.interpreter(map);
System.out.println(" sub计算结果=======>" + subresult + " ");
return subresult;
}
}
3.6 创建解析器封装器
public class Calculator {
private Expression expression;
public Calculator(String expStr) {
// 定义一个栈,安排运行的先后执行
Stack<Expression> stack = new Stack<>();
// 表达式拆分为字节数据
char[] charArray = expStr.toCharArray();
Expression left;
Expression right;
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));
System.out.println("left: " + left + " right==>" + right + " stack中的值======>" + stack.toString());
break;
case '-':
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new SubExpression(left, right));
System.out.println("left: " + left + " right==>" + right + " stack中的值======>" + stack.toString());
break;
default:
// 公式中的变量
stack.push(new VarExpression(String.valueOf(charArray[i])));
System.out.println("stack中的值======>" + stack.toString());
}
}
// 把运算结果抛出来
this.expression = stack.pop();
}
// 开始运算
public int run(HashMap<String, Integer> map) {
return this.expression.interpreter(map);
}
}
3.7 客户端代码
public class Client {
public static void main(String[] args) throws Exception {
String expStr = getExpStr();
Calculator calculator = new Calculator(expStr);
// 赋值
HashMap<String, Integer> var = getVar(expStr);
System.out.println("运算结果为:" + expStr + "=" + calculator.run(var));
}
private static HashMap<String, Integer> getVar(String expStr) throws Exception {
HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
// 解析几个参数要传递
for (char ch : expStr.toCharArray()) {
if (ch != '+' && ch != '-') {
// 解决重复参数的问题
if (!hashMap.containsKey(String.valueOf(ch))) {
System.out.println("请输入变量" + ch + "的值: ");
String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
hashMap.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return hashMap;
}
private static String getExpStr() throws IOException {
System.out.println("请输入表达式");
return (new BufferedReader(new InputStreamReader(System.in))).readLine();
}
}
运行截图:
4.解释器的优点:
解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的表达式就可以了,若扩展语法,则只要增加规则类就可以了,例如add,sub。
5.解释器的缺点
- 解释器模式会引起类膨胀:一个规则加一个类
- 解释器模式采用递归调用方法:如果程序报错了,一步步调试下去,非常复杂
- 效率问题:解释器模式由于使用了大量的循环和递归,效率是一个不容忽视的问题,特别是一用于解析复杂、冗长的语法时,效率是难以忍受的。
6.解释器的应用场景
- 重复发生的问题可以使用解释器模式
- 一个简单语法需要解释的场景
7.解释器模式注意事项
尽量不要在重要的模块中使用解释器模式,否则维护会是一个很大的问题。在项目中可以使用shell、JRuby、Groovy等脚本语言来代替解释器模式,弥补Java编译型语言的不足。我所在公司是金融证券公司,涉及到很多业务类型的计算场景。我们的计算组件采用的时候MVEL表达式的方式进行计算,使用起来美滋滋的。准备使用解释器模式的时候,可以百度搜一下Expression4J、MESP(Math Expression String Parser)、Jep等开源的解析工具包。功能都异常强大,而且非常容易使用,效率也还不错,实现大多数的数学运算完全没有问题。总之,就是有大佬开发的现成的工具,直接拿来用就好了

浙公网安备 33010602011771号