《Head First 设计模式》笔记20

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、正则表达式、符号处理引擎等。

模式结构

解释器模式主要包含如下几个角色:

  • AbstractExpression: 抽象表达式。声明一个抽象的解释操作,该接口为抽象语法树中所有的节点共享。

  • TerminalExpression: 终结符表达式。实现与文法中的终结符相关的解释操作。实现抽象表达式中所要求的方法。文法中每一个终结符都有一个具体的终结表达式与之相对应。

  • NonterminalExpression: 非终结符表达式。为文法中的非终结符相关的解释操作。

  • Context: 环境类。包含解释器之外的一些全局信息。

  • Client: 客户类。

抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 在解释器模式中由于每一种终结符表达式、非终结符表达式都会有一个具体的实例与之相对应,所以系统的扩展性比较好。

模式实现

现在我们用解释器模式来实现一个基本的加、减、乘、除和求模运算。例如用户输入表达式 3 * 4 / 2 % 4,输出结果为 2。下图为该实例的 UML 结构图:

抽象表达式:Node.java。

public interface Node {
    public int interpret();
}

非终结表达式:ValueNode.java。主要用解释该表达式的值。

public class ValueNode implements Node {
    private int value;

    public ValueNode(int value) {
        this.value=value;
    }
    public int interpret() {
        return this.value;
    }
}

终结表达式抽象类,由于该终结表达式需要解释多个运算符号,同时用来构建抽象语法树:

public abstract class SymbolNode implements Node {
    protected Node left;
    protected Node right;

    public SymbolNode(Node left,Node right) {
        this.left=left;
        this.right=right;
    }
}

MulNode.java

public class MulNode extends SymbolNode {
    public MulNode(Node left,Node right) {
        super(left,right);
    }
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}

ModNode.java

public class ModNode extends SymbolNode {
    public ModNode(Node left,Node right) {
        super(left,right);
    }
    public int interpret() {
        return super.left.interpret() % super.right.interpret();
    }
}

DivNode.java

public class DivNode extends SymbolNode {
    public DivNode(Node left,Node right) {
        super(left,right);
    }

    public int interpret() {
        return super.left.interpret() / super.right.interpret();
    }
}

Calculator.java

public class Calculator{
    private String statement;
    private Node node;

    public void build(String statement){
        Node left=null,right=null;
        Stack stack=new Stack();

        String[] statementArr=statement.split(" ");

        for (int i=0; i<statementArr.length; i++) {
            if (statementArr[i].equalsIgnoreCase("*")) {
                left=(Node)stack.pop();
                int val=Integer.parseInt(statementArr[++i]);
                right=new ValueNode(val);
                stack.push(new MulNode(left,right));
            } else if (statementArr[i].equalsIgnoreCase("/")) {
                left=(Node)stack.pop();
                int val=Integer.parseInt(statementArr[++i]);
                right=new ValueNode(val);
                stack.push(new DivNode(left,right));
            } else if(statementArr[i].equalsIgnoreCase("%")) {
                left=(Node)stack.pop();
                int val=Integer.parseInt(statementArr[++i]);
                right=new ValueNode(val);
                stack.push(new ModNode(left,right));
            } else {
                stack.push(new ValueNode(Integer.parseInt(statementArr[i])));
            }
        }
        this.node=(Node)stack.pop();
    }

    public int compute()
        return node.interpret();
    }
}

客户端:Client.java

public class Client{
    public static void main(String args[]){
        String statement = "3 * 2 * 4 / 6 % 5";

        Calculator calculator = new Calculator();

        calculator.build(statement);

        int result = calculator.compute();

        System.out.println(statement + " = " + result);
    }
}

运行结果:3 * 2 * 4 / 6 % 5 = 4

优缺点

优点

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

缺点

  1. 执行效率比较低,可利用场景比较少。
  2. 解释器模式为文法中的每一条规则至少定义了一个类,因此包含了许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其它的技术如语法分析程序或编译器生成器来处理。

参考

https://blog.csdn.net/chenssy/article/details/12719973


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]