一、定义
解释器(Interpreter)模式的定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
二、结构
解释器模式的结构
解释器模式包含以下主要角色。
1)抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
3)非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
4)环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
5)客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
结构图
三、代码实现
- 框架代码
1 public class Client { 2 public static void main(String[] args) { 3 4 } 5 } 6 7 // 抽象表达式 8 interface AbstractExpression { 9 // 解释方法 10 Object interpret(String info); 11 } 12 13 // 终结表达式 14 class TerminalExpression implements AbstractExpression { 15 16 @Override 17 public Object interpret(String info) { 18 // 对终结符表达式的处理 19 return null; 20 } 21 } 22 23 // 非终结表达式 24 class NonTerminalExpression implements AbstractExpression { 25 26 private AbstractExpression exp1; 27 private AbstractExpression exp2; 28 29 @Override 30 public Object interpret(String info) { 31 // 非对终结符表达式的处理 32 return null; 33 } 34 } 35 36 // 环境类 37 class Context { 38 private AbstractExpression exp; 39 40 public void parse(String info){ 41 // 解析信息 42 } 43 44 public Object getValue() { 45 // 调用相关表达式类的解释方法 46 return null; 47 } 48 }
- 具体解析器:加法表达式解析器,如将字母表达式"abc+cba",解析成算数表达"123+321"的值,代码如下:
1 public class Client { 2 public static void main(String[] args) { 3 Context context = new Context(); 4 context.parse("abc+cba"); 5 System.out.println(context.getValue()); 6 } 7 } 8 9 10 // 抽象表达式 11 interface AbstractExpression { 12 // 解释方法 13 Object interpret(String info); 14 } 15 16 // 终结表达式 17 class TerminalExpression implements AbstractExpression { 18 19 @Override 20 public Object interpret(String info) { 21 // 对终结符表达式的处理 22 // abc ==> 123,将abc解析成123 23 char[] chars = info.toCharArray(); 24 StringBuffer sb = new StringBuffer(); 25 for (char c : chars) { 26 sb.append(c - 'a' + 1); 27 } 28 return Integer.parseInt(sb.toString()); 29 } 30 } 31 32 // 非终结表达式 33 class NonTerminalExpression implements AbstractExpression { 34 35 private AbstractExpression exp1; 36 private AbstractExpression exp2; 37 38 @Override 39 public Object interpret(String info) { 40 // 非对终结符表达式的处理 41 String[] strings = info.split("[+]"); 42 exp1 = new TerminalExpression(); 43 exp2 = new TerminalExpression(); 44 int value = (Integer) exp1.interpret(strings[0]) + (Integer)exp2.interpret(strings[1]); 45 return value; 46 } 47 } 48 49 // 环境类 50 class Context { 51 private AbstractExpression exp; 52 private String info; 53 54 public void parse(String info){ 55 // 解析信息 56 if (info.indexOf('+') > -1) { 57 exp = new NonTerminalExpression(); 58 }else { 59 exp = new TerminalExpression(); 60 } 61 this.info = info; 62 } 63 64 public Object getValue() { 65 // 调用相关表达式类的解释方法 66 return exp.interpret(info); 67 } 68 }
四、源码应用
1、JEP中的应用
JEP是Java expression parser的简称,即java表达式分析器,Jep是一个用来转换和计算数学表达式的java库。通过这个程序包,用户可以以字符串的形式输入一个、任意的公式,然后快速地计算出结果。Jep支持用户自定义变量、常量和函数。包括许多常用的数学函数和常。
简单的来说,就是可以用算术运算符代替之前的java的公式,显示和逻辑编写更加清晰简单
- 引入JEP依赖
1 <!-- Jep 是 Java expression parser 的简称 --> 2 <dependency> 3 <groupId>jep</groupId> 4 <artifactId>jep</artifactId> 5 <version>2.24</version> 6 </dependency>
-
代码示例
1 public class JepClient { 2 public static void main(String[] args) { 3 JEP jep = new JEP(); 4 // 定义要计算的数据表达式 5 String 存款利息 = "本金*利率*时间"; 6 // 给相关变量赋值 7 jep.addVariable("本金", 10000); 8 jep.addVariable("利率", 0.038); 9 jep.addVariable("时间", 2); 10 // 解析表达式 11 jep.parseExpression(存款利息); 12 // 计算 13 Double accrual = jep.getValue(); 14 System.out.println("存款利息:" + accrual); 15 } 16 }
2、Spring源码应用
-
Spring 框架中 SpelExpressionParser 就使用到解释器模式
-
代码分析+Debug源码
测试demo
1 public static void main(String[] args) { 2 SpelExpressionParser parser = new SpelExpressionParser(); 3 Expression expression = parser.parseExpression("100 * (2 + 400) * 1 + 66"); 4 Integer value = (Integer) expression.getValue(); 5 System.out.println(value); 6 }