美文网首页
解释器模式的使用

解释器模式的使用

作者: 文景大大 | 来源:发表于2022-07-02 13:05 被阅读0次

一、模式介绍

解释器模式就是定义多种解释器,为文本或者符号进行解释行为的逻辑意义,比如1+2,需要两种解释器,一种数值解释器告诉我们1和2这种符号代表就是数值1和2,还有一种就是符号解释器,告诉我们+号代表的是前后两个数值做加法运算。因此我们可以看出,解释器模式就像是我们的代码编译器,将固定文法的内容进行解释,构建出计算机能识别的内容进行计算。

核心就是:识别文法(符号)、构建解释。一般包含如下三种角色:

  • 抽象表达式,负责定义解释符号或者文本的方法,然后由其子类实现具体的解释逻辑;
  • 终结符表达式,实现与终结符有关的解释操作,比如“1+1-2”这个表达式里面,1和2就是终结符表达式;
  • 非终结符表达式,实现与非终结符有关的解释操作,比如“1+1-2”这个表达式里面,+和-符号就是终结符表达式;
  • 上下文环境类,用来对文本或者符号进行分类,然后调用各种解释器进行解释;

我们以一个计算整数加减法的计算器为例:

/**
 * 抽象表达式,定义解释符号的行为
 */
public abstract class Expression {
    public abstract int interpreter(HashMap<String,Integer> var);
}
/**
 * 数值表达式,对自然数符号进行解释
 */
public class VarExpression extends Expression{
    private String name;

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

    /**
     * 自然数符号的解释就是返回当前name对应的数值
     * @param var
     * @return
     */
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return var.get(name);
    }
}
/**
 * 运算符表达式,对运算符进行解释
 */
public class SymbolExpression extends Expression{
    protected Expression left;
    protected Expression right;

    public SymbolExpression(Expression left, Expression right){
        this.left = left;
        this.right = right;
    }

    /**
     * 运算符分为加号运算符和减号运算符,具体解释逻辑需要在子类中实现
     * @param var
     * @return
     */
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return 0;
    }
}
/**
 * 加号运算符表达式,对加号运算符进行解释
 */
public class AddExpression extends SymbolExpression{
    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    /**
     * 加号运算符的解释就是两数相加的结果
     * @param var
     * @return
     */
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}
/**
 * 减号运算符表达式,对减号运算符进行解释
 */
public class SubExpression extends SymbolExpression{
    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    /**
     * 减号运算符的解释就是两数相减的结果
     * @param var
     * @return
     */
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return super.left.interpreter(var) - super.right.interpreter(var);
    }
}
public class Calculator {
    private Expression expression;

    public Calculator(String expressionStrings){
        // 使用栈这种数据结构来处理加减运算
        Stack<Expression> stack = new Stack<>();
        char[] chars = expressionStrings.toCharArray();
        Expression left = null;
        Expression right = null;

        // 1+1-2这样的表达式在如下循环后,stack中只会有有一个元素
        for (int i=0;i<chars.length;i++){
            switch (chars[i]) {
                case '+':
                    // 取出第一个加数
                    left = stack.pop();
                    // 获取第二个加数
                    right = new VarExpression(String.valueOf(chars[++i]));
                    // 构造加号表达式后再入栈,等待和后面的表达式进行递归计算
                    stack.push(new AddExpression(left,right));
                    break;
                case '-':
                    // 取出被减数
                    left = stack.pop();
                    // 获取减数
                    right = new VarExpression(String.valueOf(chars[++i]));
                    // 构造减号表达式后再入栈,等待和后面的表达式进行递归计算
                    stack.push(new SubExpression(left,right));
                    break;
                default:
                    // 数值符号,name就指定为当前数值,再入栈,等待和后面的表达式进行递归计算
                    stack.push(new VarExpression(String.valueOf(chars[i])));
                    break;
            }
        }

        // 获取stack中最终形成的唯一的元素
        this.expression = stack.pop();
    }

    /**
     * 对当前表达式进行递归解释
     * @param var
     * @return
     */
    public int doCalculate(HashMap<String, Integer> var){
        return this.expression.interpreter(var);
    }
}
@Slf4j
public class Main {
    public static void main(String[] args) {
        String expressionStrins = "a+b-c";
        HashMap<String,Integer> vars = new HashMap<>();
        vars.put("a",1);
        vars.put("b",1);
        vars.put("c",2);

        Calculator casio = new Calculator(expressionStrins);
        Integer result = casio.doCalculate(vars);
        log.info("计算结果为:{}", result);
    }
}

二、使用场景

  • JDK中Pattern对正则表达式的编译和解析;
  • Spring中ExpressionParser接口的使用;

三、模式总结

3.1 优点

  • 符号语法是由各个解释器类负责解释的,当符号表达的含义需要变更时,只需要对应的解释类即可,当需要增加新的符号时,也只需要增加新的解释器类即可,符合开闭原则;
  • 提供给我们一种新的用来解释表达式的方法;
  • 比较适合解释语法规则简单的场景;

3.2 缺点

  • 每个新的符号语法都要新增一个解释器,当符号种类比较多的时候,就会产生大量的解释类,增加系统的维护难度;
  • 解释器模式使用到了递归的思想,当表达式较长,递归深度就会很深,比较占用资源,解释效率就会下降,且很难调试;

相关文章

  • 17.解释器模式(行为型)

    解释器模式(行为型) 解释器模式很难学,使用率很低! 一、相关概念 1). 解释器模式概述 解释器模式是一种使用频...

  • java设计模式15(解释器模式)

    解释器模式用于描述如何构成一个简单的语言解释器,主要应用于使用面向对象语言开发的解释器的设计。 解释器模式的定义:...

  • spring框架中的设计模式一

    Spring框架中使用的4种设计模式:解释器,构建器,工厂方法和抽象工厂。 解释器设计模式 此模式基于表达式和评估...

  • 行为模式-解释器模式*

    标签(空格分隔):解释器模式 解释器模式:给定一个语言,定义它文法的一种表示,并定义一个解释器,这个解释器使用该表...

  • 解释器模式的使用

    一、模式介绍 解释器模式就是定义多种解释器,为文本或者符号进行解释行为的逻辑意义,比如1+2,需要两种解释器,一种...

  • 设计模式笔记(23)--解释器模式

    解释器模式 GOF对于解释器模式的定义是:“给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用...

  • 二十五、解释器模式

    1. 何为解释器模式 解释器模式():给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示...

  • 解释器模式-行为型模式

    解释器模式用于在有大量文法需要转换时使用。如字符串模式匹配,语言转换等。 代码结构: 解释器类抽象类:解释器类持有...

  • javascript设计模式——解释器模式

    解释器模式:对于一种语言,给出其文法表示形式,并定义一种解释器,通过使用这种解释器来解释语言中定义的句子使用场景:...

  • 第5章 -行为型模式-解释器模式(终)

    一、解释器模式的简介 二、解释器模式的优缺点 三、解释器模式的实例

网友评论

      本文标题:解释器模式的使用

      本文链接:https://www.haomeiwen.com/subject/uwqkbrtx.html