设计模式之——解释器模式

简介

今天给大家介绍的设计模式叫做“解释器模式”,该模式是“行为型设计模式”中的一员。

解释器模式的核心思想是:给定一个语言,定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子。

听完这句话话是不是顿时感觉一脸懵?什么语言、文法、句子,都是些什么鬼?

在这里插入图片描述

别慌让“菜鸟”来给你分析一波。

文法:可以将其理解为一种规则,就好比汉语中一句话必须由“主谓宾”三者构成一样。
句子:符合文法规则的一种表现,可以简单理解成符合汉语规则的一句话。
语言:将所有句子汇集起来的一个集合就是语言。

我们可以通过解释器将语言中的句子解析成一颗语法树,从而对其进行操作。所谓的语法树就是将句子通过文法进行推导,进而获取到句子的一棵树形表现形式。

解释器模式UML类图

在这里插入图片描述

类图讲解

Context:环境角色(上下文),含有每个解释器所需的一些数据或全局的一些信息。
AbstractExpression:抽象表达式类,声明了抽象的解释操作,所有解释器类都继承或实现该类。
TerminalExpression:终结符表达式类,是AbstractExpression的子类,实现了文法中有关终结符相关的解释操作。
TerminalExpression:非终结符表达式,AbstractExpression的子类,该类的功能与终结表达式类相反,文法中所有非终结符由该类进行解释。
Client:客户端测试类。

案例讲解

下面让我们通过一个经典的“计算器”案例来详细了解一下解释器模式。

注:本文重点讲解的是解释器模式故示例代码只实现了加减法的运算。

表达式接口

public interface Expression {

  /**
   * 解释表达式的抽象方法
   *
   * @param map 比如现有表达式:a + b;那么map中存放的就是{a=10,b=20}
   * @return 返回解释后的值。
   */
  int interpreter(Map<String, Integer> map);

}

变量解析器类

public class VarExpression implements Expression {

  // 公式中的变量。
  private String key;

  public VarExpression(String key) {
    this.key = key;
  }

  // 通过key获取所对应的值
  @Override
  public int interpreter(Map<String, Integer> map) {
    return map.get(key);
  }
}

运算符解析器类

public class SymbolExpression implements Expression {

  /**
   * 假如现有表达式:a + b - c 需要解析。
   * 分析:
   *  1、一个运算符连接的是它左右两个数字。
   *  2、如上表达式【+】号连接的是吧“a"和"b",【-】号连接的是"a + b"和“c”。
   *  3、经次分析我们将运算符连接的左右都看成是一个表达式也就是Expression。
   */

  // 左表达式
  protected Expression leftExpression;
  // 右表达式
  protected Expression rightExpression;

  public SymbolExpression(Expression leftExpression, Expression rightExpression) {
    this.leftExpression = leftExpression;
    this.rightExpression = rightExpression;
  }

  // 不同种类的运算符由不同的运算符子类进行解析,所以该类不实现interpreter方法。
  @Override
  public int interpreter(Map<String, Integer> map) {
    return 0;
  }
}

减法解析器

public class SubExpression extends SymbolExpression {

  public SubExpression(Expression leftExpression, Expression rightExpression) {
    super(leftExpression, rightExpression);
  }

  // 解释减法
  @Override
  public int interpreter(Map<String, Integer> map) {
    return leftExpression.interpreter(map) - rightExpression.interpreter(map);
  }
}

加法解析器

public class AddExpression extends SymbolExpression {

  public AddExpression(Expression leftExpression, Expression rightExpression) {
    super(leftExpression, rightExpression);
  }

  // 解释加法
  @Override
  public int interpreter(Map<String, Integer> map) {
    return leftExpression.interpreter(map) + rightExpression.interpreter(map);
  }
}

计算器 => 对应Context角色

public class Calculator {

  // 表达式
  private Expression expression;

  public Calculator(String strExpression) {
    char[] charArray = strExpression.toCharArray();
    // 定义栈用于存储表达式,因示例简单故不考虑运算顺序。
    Stack<Expression> stack = new Stack<>();
    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));
          break;
        case '-':
          // 过程跟加法一样
          left = stack.pop();
          right = new VarExpression(String.valueOf(charArray[++i]));
          stack.push(new SubExpression(left, right));
          break;
        default:
          // 不是运算符
          stack.push(new VarExpression(String.valueOf(charArray[i])));
          break;
      }
    }
    // 遍历完成获取最终解析好的表达式。
    this.expression = stack.pop();
  }

  /**
   *
   * @param map 表达式对应的值
   * @return 计算的结果
   */
  public int calculate(Map<String, Integer> map) {
    return this.expression.interpreter(map);
  }
}

客户端测试类

public class Client {

  public static void main(String[] args) {
    // 表达式
    String strExpression = "a+b-c+d";
    // 表达式对应的值
    Map<String, Integer> map = new HashMap<>();
    map.put("a", 2);
    map.put("b", 10);
    map.put("c", 8);
    map.put("d", 13);
    // 创建计算器
    Calculator calculator = new Calculator(strExpression);
    // 计算
    int result = calculator.calculate(map);
    System.out.println("表达式:" + strExpression + "的计算结果为:" + result);
  }
}

执行结果

在这里插入图片描述

总结

1、使用解释器模式可以提高代码的可扩展性。

2、使用解释器模式会引起类膨胀。

3、解释器模式会采用递归调用方法,可能会降低效率,并且会提高维护和调试的成本。

4、解释器模式的使用场景比较少,开发中也不经常接触到,一般常用在编译器、运算表达式计算、正则表达式解析等。

今天的分享就到这里了,如果感觉“菜鸟”写的文章还不错,记得点赞关注呦!你们的支持就是我坚持下去的动力。文章哪里写的有问题的也希望大家可以指出,我会虚心受教。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值