• 【设计模式】解释器模式


    一、定义

      解释器(Interpreter)模式的定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。

    二、结构

    解释器模式的结构

    解释器模式包含以下主要角色。
      1)抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。

      2)终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。

      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 }
    View Code

    四、源码应用

    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源码应用

    1. Spring 框架中 SpelExpressionParser 就使用到解释器模式

    2. 代码分析+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     }
  • 相关阅读:
    朴素贝叶斯小结
    Logistic回归小结
    线性回归小结
    Zabbix使用采坑记录
    cookie与session测试关注点
    JMeter笔记十二:逻辑控制器之事务控制器、模块控制器和吞吐量控制器
    JMeter笔记十一:逻辑控制器之随机控制器、随机顺序控制器和交替控制器
    JMeter笔记十:逻辑控制器之ForEach控制器
    JMeter笔记九:逻辑控制器之循环控制器、While控制器
    JMeter笔记八:逻辑控制器之如果(If)控制器、仅一次控制器、Switch控制器
  • 原文地址:https://www.cnblogs.com/h--d/p/14718900.html
Copyright © 2020-2023  润新知