设计模式之解释器模式

介绍

解释器(Interpreter)模式的定义:

一种行为型设计模式。定义了一个解释器,来解释给定语言和文法的句子。其实质是把语言中的每个符号定义成一个(对象)类,从而把每个程序转换成一个具体的对象树。

案例

角色构成:

  • AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。
  • TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。
  • NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
  • Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。

这里我们编写一个案例:张三公司最近需要开发一款简单的加法/减法解释器,只要输入一个加法/减法表达式,它就能够计算出表达式结果,当输入字符串表达式为“1+2+3+4-5”时,将输出计算结果为3。

在这里插入图片描述
抽象表达式类

// 抽象表达式类
public abstract class AbstractExpression {
    // 提供统一的解释接口
    public abstract int interpret();
}

终结符类

// 终结符类
public class ValueExpression extends AbstractExpression {
    private int value;

    public ValueExpression(int value) {
        this.value = value;
    }

    @Override
    public int interpret() {
        return value;
    }
}

非终结符加法类

public class AddExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public AddExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

非终结符减法类

public class SubtractionExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public SubtractionExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() - right.interpret();
    }
}

上下文计算器类

public class Calculator {

    private AbstractExpression expression;

    public void parse(String expression) {
        String[] expressionArray = expression.split("");
        Stack<AbstractExpression> stack = new Stack<>();
        for (int i = 0; i < expressionArray.length; i++) {
            if ("+".equals(expressionArray[i])) {
                AbstractExpression left = stack.pop();
                AbstractExpression right = new ValueExpression(Integer.parseInt(expressionArray[++i]));
                stack.push(new AddExpression(left, right));
            } else if ("-".equals(expressionArray[i])) {
                AbstractExpression left = stack.pop();
                AbstractExpression right = new ValueExpression(Integer.parseInt(expressionArray[++i]));
                stack.push(new SubtractionExpression(left, right));
            } else {
                stack.push(new ValueExpression(Integer.parseInt(expressionArray[i])));
            }
        }
        this.expression = stack.pop();
    }

    public int calculate() {
        return expression.interpret();
    }
}

客户端类

public class Client {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        String expression = "1+2+3+4-5";
        calculator.parse(expression);
        System.out.println(expression + "=" + calculator.calculate());
    }
}

运行结果

1+2+3+4-5=5

优缺点及应用场景

优点:

  • 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
  • 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。

缺点:

  • 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
  • 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
  • 可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。

应用场景:

  • 当语言的文法较为简单,且执行效率不是关键问题时。
  • 当问题重复出现,且可以用一种简单的语言来进行表达时。
  • 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。

注意:解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。如果碰到对表达式的解释,在 Java 中可以用 Expression4J 或 Jep 等来设计。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值