目录
  1. 1. 解释器模式
    1. 1.1. 定义
    2. 1.2. 解释器模式示意图
    3. 1.3. 流程
    4. 1.4. 代码实现
      1. 1.4.1. 表达式
      2. 1.4.2. 计算器
      3. 1.4.3. 场景实现
    5. 1.5. 应用场景
    6. 1.6. 解释器模式的优缺点
      1. 1.6.1. 优点
      2. 1.6.2. 缺点
      3. 1.6.3. 注意事项
解释器模式

解释器模式

定义

Given a language,define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

解释器模式示意图

解释器模式

流程

  1. 定义一个总的抽象表达式类,是所有表达式的父类。表达式又分为变量表达式和符号表达式。
  2. 变量表达式需要输入公式变量与数字的映射关系,通过映射关系用公式变量取出对应的具体数字,将具体数字套入公式。
  3. 抽象符号表达式类是所有符号运算类的父类,符号运算包括加减乘除的运算规则。
  4. 通过客户端提供公式以及公式变量与数字的映射关系,将这两个输入计算器对象中,按多态性来根据公式符号选择需要的符号解释器,将公式变量与数字的映射关系输入变量解释器,将对应的数字套入结果表达式中,获取最终结果。

代码实现

表达式

  1. 抽象表达式Expression
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example.interpreter;

import java.util.HashMap;

/**
* 抽象表达式,用来组合不同种类的解释器,形成一个表达式。
* 每种解释器就是一个算术因子,是加减乘除需要的算术因子。
*/
public abstract class Expression {
/**
* @param var String是表达式中的值,Integer是表达式中值的索引值
* @return 返回表达式计算出的值
*/
public abstract int interpreter(HashMap<String , Integer> var);
}
  1. 变量表达式VarExpression
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.example.interpreter;

import java.util.HashMap;

public class VarExpression extends Expression {
private String key ;

public VarExpression(String key){
this.key = key ;
}
/**
* 用来从输入的变量中获取变量在表达式中的位置
* @param var String是表达式中的值,Integer是表达式中值的索引值
* @return
*/
@Override
public int interpreter(HashMap<String, Integer> var) {
return var.get(key);
}
}
  1. 抽象符号表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.example.interpreter;

import java.util.HashMap;

/**
* 符号解释器,用来解释表达式中的运算符号
*/
public abstract class SymbolExpression extends Expression {
protected Expression left ;
protected Expression right ;

public SymbolExpression(Expression left , Expression right){
this.left = left ;
this.right = right ;
}
}
  1. 加法表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.example.interpreter;

import java.util.HashMap;

public class AddExpression extends SymbolExpression {
/**
* 从抽象符号表达式中继承计算的左值和右值
* @param left
* @param right
*/
public AddExpression(Expression left, Expression right) {
super(left, right);
}

@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) + super.right.interpreter(var);
}
}
  1. 减法表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.example.interpreter;

import java.util.HashMap;

/**
* 减法解释器
*/
public class SubExpression extends SymbolExpression{

/**
* 从抽象符号表达式中继承计算的左值和右值
* @param left
* @param right
*/
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);
}
}
  1. 乘法表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.example.interpreter;

import java.util.HashMap;

/**
* 乘法解释器
*/
public class MulExpression extends SymbolExpression {

/**
* 从抽象符号表达式中继承计算的左值和右值
* @param left
* @param right
*/
public MulExpression(Expression left, Expression right) {
super(left, right);
}

@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) * super.right.interpreter(var) ;
}
}
  1. 除法表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example.interpreter;

import java.util.HashMap;

public class DivExpression extends SymbolExpression {

public DivExpression(Expression left, Expression right) {
super(left, right);
}

@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) / super.right.interpreter(var) ;
}
}

计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package org.example.interpreter;

import java.util.HashMap;
import java.util.Stack;

public class Calculator {
private Expression expression ;
public Calculator(String expStr){
Stack<Expression> stack = new Stack<>();
Expression left = null ;
Expression right = null ;

System.out.println(expStr);
char[] array = expStr.toCharArray();
for (int i=0 ; i<array.length ; i++){
switch (array[i]){
case '+' :
left = stack.pop(); // 如果现在是+这个符号,表示前面有一个数已经入栈,这个已经入栈的数就是左值
right = new VarExpression(String.valueOf(array[++i])); //获取符号后面的数值作为右值
stack.push(new AddExpression(left , right)); // 将计算结果压栈
break;
case '-' :
left = stack.pop();
right = new VarExpression(String.valueOf(array[++i]));
stack.push(new SubExpression(left , right)) ;
break;
case '*' :
left = stack.pop();
right = new VarExpression(String.valueOf(array[++i]));
stack.push(new MulExpression(left , right)) ;
break;
case '/' :
left = stack.pop() ;
right = new VarExpression(String.valueOf(array[++i]));
stack.push(new DivExpression(left , right)) ;
break;
default:
stack.push(new VarExpression(String.valueOf(array[i]))) ;
break;
}
}
this.expression = stack.pop() ; // 将最终的运算结果赋值
}

public int run(HashMap<String , Integer> var){
return this.expression.interpreter(var) ;
}
}

场景实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class App {
/**
* 解释器模式
* @param args
*/
public static void main(String[] args) {
/* 公式变量与数字的映射关系 */
HashMap<String, Integer> map = new HashMap<>();
map.put("a" , 100);
map.put("b" , 20);
map.put("c" , 30);
/* 需要的公式模板 */
String expStr = "a+b-c";
Calculator calculator = new Calculator(expStr);
System.out.println(calculator.run(map));
}
}

应用场景

  1. 重复发生的问题,规则不同,但是有相同的元素,久可以使用解释器模式。
  2. 一个简单语法需要解释。如果是复杂语法,会导致类膨胀。

解释器模式的优缺点

优点

  1. 解释器是一个简单的语法分析工具,优点是扩展性,修改语法规则只需要修改对应的符号表达式就行了。

缺点

  1. 会引起类膨胀,每种语法都会产生一个规则类,语法规则很复杂时会产生很多规则类。
  2. 解释器模式采用递归调用,使用栈。调试非常麻烦。
  3. 解释器模式使用递归和栈,效率很低。

注意事项

  1. 不要在重要模块使用解释器模式,这样会导致很难维护。
  2. 解释器模式在实际中很少使用,主要在数据分析工具、报表设计工具、科学计算工具使用。
  3. 可以使用Expression4J,MESP,Jep开源解析工具来代替自己写解释器模式。
文章作者: rack-leen
文章链接: http://yoursite.com/2019/05/19/Java/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/%E8%A7%A3%E9%87%8A%E5%99%A8%E6%A8%A1%E5%BC%8F/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 rack-leen's blog
打赏
  • 微信
  • 支付宝

评论