天天看点

设计模式——行为型——解释器模式

一、理论

解释器模式(Interpreter Pattern)是一种按照规定语法进行解析的方案,在现在项目中使用较少,其定义如下:

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

设计模式——行为型——解释器模式
  • AbstractExpression——抽象解释器

    AbstractExpression角色定义了语法树节点的共同接口(API)

  • TerminalExpression——终结符表达式

    实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。

  • NonterminalExpression——非终结符表达式

    文法中的每条规则对应于一个非终结表达式,非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

  • Context——环境角色

    含有解释器之外的全局信息

在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器。

二、代码

模拟一个加减计算器:

设计模式——行为型——解释器模式

AbstractExpression——抽象解释器

public abstract class Expression {
    public abstract int interpreter(HashMap<String, Integer> var);
}
           

TerminalExpression——终结符表达式

public class VarExpression extends Expression {

    private String key;

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

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return var.get(this.key);
    }
}
           

NonterminalExpression——非终结符表达式

public abstract class SymbolExpression extends Expression {
    protected Expression left;
    protected Expression right;

    //每个解析公式只需要关心自己左右的表达式的结果
    public SymbolExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
}
           
public class AddSymbolExpression extends SymbolExpression {
    public AddSymbolExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}

           
public class MinusSymbolExpression extends SymbolExpression {
    public MinusSymbolExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return left.interpreter(var) - right.interpreter(var);
    }
}
           

计算器和测试类:

public class Calculator {
    private Expression expression;

    public Calculator(String expStr) {
        Stack<Expression> stack = new Stack<>();
        char[] charArray = expStr.toCharArray();
        Expression left = null;
        Expression right = null;
        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 AddSymbolExpression(left, right));
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new MinusSymbolExpression(left, right));
                    break;
                default:
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
                    break;
            }
        }
        this.expression = stack.pop();
    }

    public int run(HashMap<String, Integer> var) {
        return this.expression.interpreter(var);
    }
}
           
public class Client {
    public static void main(String[] args) throws IOException {
        String expStr = getExpStr();
        HashMap<String, Integer> map = getValue(expStr);
        Calculator calculator = new Calculator(expStr);
        System.out.println("计算机构:" + expStr + "=" + calculator.run(map));
    }

    public static String getExpStr() throws IOException {
        System.out.println("请输入表达式");
        return new BufferedReader(new InputStreamReader(System.in)).readLine();
    }
    //Context角色
    public static HashMap<String, Integer> getValue(String expStr) throws IOException {
        HashMap hashMap = new HashMap();
        for (char c : expStr.toCharArray()) {
            if (c != '+' && c != '-') {
                if (!hashMap.containsKey(String.valueOf(c))) {
                    System.out.println("请输入" + String.valueOf(c) + "的值:");
                    String in = new BufferedReader(new InputStreamReader(System.in)).readLine();
                    hashMap.put(String.valueOf(c), Integer.valueOf(in));
                }
            }
        }
        return hashMap;
    }
}
           

三、总结

  1. 当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程序具有良好的扩展性
  2. 应用场景:编译器、运算表达式计算、正则表达式、机器人等
  3. 使用解释器可能带来的问题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低.

继续阅读