设计模式--解释器模式

  1. 解释器模式就是定义语言的文法,并且建立一个解释器来解释该语言中的句子

  2. 解释器模式的UML图

    在这里插入图片描述

  3. AbstractExpression抽象表达式。TerminalExpression,终结符表达式,解释结果的;NonterminalExpression,非终结符表达式,一般以子类的形式出现;Context,环境类,存储符号和其他信息,以便于获取解释结果之前的存储;Client客户类

  4. 解释器模式通过将表达式转化成语法树,然后逐级计算得到最终计算的结果

  5. 解释器模式的代码实现

    1. 创建一个抽象解释器接口

      /**
       * 抽象解释器,提供了元素与元素之间的计算方式以及计算过程
       */
      public interface Node {
      
          int interpret();
      }
      
    2. 创建终结解释器类并实现抽象解释器

      /**
       * 终结解释器(返回最终的结果),这个Node能够代表数学表达式中数字部分的展现
       */
      public class ValueNode implements Node {
      
          private int value;
      
          public ValueNode(int value) {
              this.value = value;
          }
      
          @Override
          public int interpret() {
              return this.value;
          }
      
      }
      
    3. 创建非终结解释器抽象类实现抽象解释器

      /**
       * 非终结解释器
       */
      public abstract class SymbolNode implements Node {
      
          /**
           * 非终结解释器需要关联Node,并且分为左Node和右Node
           */
          Node nodeLeft;
          Node nodeRight;
      
          public SymbolNode(Node nodeLeft, Node nodeRight) {
              this.nodeLeft = nodeLeft;
              this.nodeRight = nodeRight;
          }
      
      }
      
    4. 创建三个具体的非终结解释器

      /**
       * 除法解释器(具体非终结解释器)
       */
      public class DivSymbolNode extends SymbolNode {
      
          public DivSymbolNode(Node nodeLeft, Node nodeRight) {
              super(nodeLeft, nodeRight);
          }
      
          @Override
          public int interpret() {
              return nodeLeft.interpret() / nodeRight.interpret();
          }
      }
      
      /**
       * 取余解释器(具体非终结解释器)
       */
      public class ModSymbolNode extends SymbolNode {
      
          public ModSymbolNode(Node nodeLeft, Node nodeRight) {
              super(nodeLeft, nodeRight);
          }
      
          @Override
          public int interpret() {
              return nodeLeft.interpret() % nodeRight.interpret();
          }
      }
      
      /**
       * 乘法解释器(具体非终结解释器)
       */
      public class MulSymbolNode extends SymbolNode {
      
          public MulSymbolNode(Node nodeLeft, Node nodeRight) {
              super(nodeLeft, nodeRight);
          }
      
          @Override
          public int interpret() {
              return nodeLeft.interpret() * nodeRight.interpret();
          }
      }
      
    5. 创建Context类

      import java.util.Stack;
      
      /**
       * 结合了Context类并且为客户端提供了统一调用接口
       * 这个类是核心解释器
       * 计算是从孙子节点里的interpret
       */
      public class Caculator {
      
          private Node node;
      
          /**
           * 待解释的语句
           */
          private String statement;
      
          /**
           * 解释可计算公式,将最终解释的结果存如stack中
           * 最终需要将Node存储到stack中(在存储之前已经确定了表达式的顺序,解释完成的结果)
           * @param statement
           */
          public void build(String statement){
              //结合了非终结解释器
              Node left = null;
              Node right = null;
      
              Stack stack = new Stack();  //context类
      
              String[] statementArr = statement.split(" ");
              for (int i = 0; i < statementArr.length; i++) {
                  if(statementArr[i].equals("*")){
                      left = (Node) stack.pop();  //获取栈顶元素,并且移除栈顶元素
                      int val = Integer.parseInt(statementArr[++i]);
                      right = new ValueNode(val);
                      stack.push(new MulSymbolNode(left, right));  //MulSymbolNode代表乘号
                  } else if(statementArr[i].equals("/")){
                      left = (Node) stack.pop();
                      int val = Integer.parseInt(statementArr[++i]);
                      right = new ValueNode(val);
                      stack.push(new DivSymbolNode(left, right));  //MulSymbolNode代表除号
                  } else if(statementArr[i].equals("%")){
                      left = (Node) stack.pop();
                      int val = Integer.parseInt(statementArr[++i]);
                      right = new ValueNode(val);
                      stack.push(new ModSymbolNode(left, right));  //MulSymbolNode代表取余
                  } else {
                      stack.push(new ValueNode(Integer.parseInt(statementArr[i])));  //传入的数字
                  }
              }
              this.node = (Node) stack.pop();  //这个Node包含了所有的数字和符号
          }
      
          /**
           * 计算build中解释的最终结果,并返回结果
           * @return
           */
          public int compute(){
              return node.interpret();
          }
      }
      
    6. 创建测试类

      public class Test {
          public static void main(String[] args) {
              String statement = "3 * 2 * 4 / 3 % 5";
              Caculator caculator = new Caculator();
              caculator.build(statement);
              System.out.println(statement +" = " + caculator.compute());
          }
      }
      
  6. 解释器模式的优点

    1. 扩展性比较好,灵活
    2. 增加了新的解释表达式的方式
    3. 易于实现文法
  7. 解释器模式的缺点

    1. 执行效率比较低,可使用场景较小
    2. 对于复杂的文法比较难维护
  8. 解释器模式的使用场景

    1. 讲一个需要解释执行的语句转成一个抽象语法树
    2. 一些重复出现的问题可以用一种简单的语句来进行表达
    3. 文法较为简单
  9. JDK中对解释器模式的使用

    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值