设计模式之解释器模式

解释器模式

概述

解释器模式是一种用得比较少的行为型模式.提供了一种解释语言的语法或表达式的方式. 通过定义一个表达式接口,解释一个特定的上下文。

其实这种模式就是定义编译原理中学习的文法的一种表示。

UML

  • AbstractExpression: 抽象表达式,声明一个抽象的解释操作父类,定义一个抽象的解释方法,具体的实现由子类解释器完成
  • TerminalExpression: 终结符表达式,实现文法中与终结符有关的解释操作,文法中每一个终结符都有一个具体的终结表达式与之对应
  • NonterminalExpression: 非终结符表达式,实现文法中与非终结符有关的解释操作
  • Context: 上下文环境类,包含解释器之外的全局信息
  • Client: 客户端,解析表达式,构建抽象语法树,执行具体的解释操作等.

应用场景

解释器设计模式

  • 某个简单的语言需要解释执行并且可以将该语言中的语句表示为一个抽象语法树的时候
  • 在某些特定的领域出现不断重复的问题时,可以将该领域的问题转化为一种语法规则下的语句,并构建解释器来解释该语句

例子

参考维基百科例子

一个解析加减法语法规则的例子

  • 抽象表达式类、以及终结符表达式类和非终结符表达式类
package com.dyleaf.behavior.InterpreterPattern;

import java.util.Map;

/**
 *抽象的解释操作父类
 */
public interface Expression {
    public int interpret(Map<String, Expression> variables);
}

/**
 * 数字解释器
 */
class Number implements Expression {
    private int number;

    public Number(int number) {
        this.number = number;
    }

    public int interpret(Map<String, Expression> variables) {
        return number;
    }
}

/**
 * 加法解释器
 */
class Plus implements Expression {
    Expression leftOperand;
    Expression rightOperand;

    public Plus(Expression left, Expression right) {
        leftOperand = left;
        rightOperand = right;
    }

    public int interpret(Map<String, Expression> variables) {
        return leftOperand.interpret(variables) + rightOperand.interpret(variables);
    }
}

/**
 * 减法解释器
 */
class Minus implements Expression {
    Expression leftOperand;
    Expression rightOperand;

    public Minus(Expression left, Expression right) {
        leftOperand = left;
        rightOperand = right;
    }

    public int interpret(Map<String, Expression> variables) {
        return leftOperand.interpret(variables) - rightOperand.interpret(variables);
    }
}

/**
 * 变量解释器
 */
class Variable implements Expression {
    private String name;

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

    public int interpret(Map<String, Expression> variables) {
        if (null == variables.get(name))
            return 0; // Either return new Evaluator(0).
        return variables.get(name).interpret(variables);
    }
}
  • 业务逻辑处理类
package com.dyleaf.behavior.InterpreterPattern;

import java.util.Map;
import java.util.Stack;

public class Evaluator implements Expression {
    private Expression syntaxTree;

    public Evaluator(String expression) {
        Stack<Expression> expressionStack = new Stack<Expression>();
        for (String token : expression.split(" ")) {
            if (token.equals("+")) {
                Expression subExpression = new Plus(expressionStack.pop(), expressionStack.pop());
                expressionStack.push(subExpression);
            } else if (token.equals("-")) {
                // it's necessary remove first the right operand from the stack
                Expression right = expressionStack.pop();
                // ..and after the left one
                Expression left = expressionStack.pop();
                Expression subExpression = new Minus(left, right);
                expressionStack.push(subExpression);
            } else
                expressionStack.push(new Variable(token));
        }
        syntaxTree = expressionStack.pop();
    }

    public int interpret(Map<String, Expression> context) {
        return syntaxTree.interpret(context);
    }
}

  • 客户端角色,包含环境角色,直接写在main函数里面了
package com.dyleaf.behavior.InterpreterPattern;

import java.util.HashMap;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        String expression = "w x z - +";
        Evaluator sentence = new Evaluator(expression);
        Map<String, Expression> variables = new HashMap<String, Expression>();
        variables.put("w", new Number(5));
        variables.put("x", new Number(10));
        variables.put("z", new Number(42));
        int result = sentence.interpret(variables);
        System.out.println(result);
    }
}

优缺点

优点

  • 灵活性强,如上边的例子,当我们想对文法规则进行扩展延伸时,只需要增加相应的非终结符解释器,并在构建语法树的时候使用新增的解释器对象进行具体的解释即可.

缺点

  • 因为每一条文法都可以对应至少一个解释器,会生成大量的类,导致后期维护困难,而且对应复杂的文法,构建语法树会显得异常繁琐.

see source code

posted @ 2018-03-05 01:53  Dyleaf  阅读(169)  评论(0编辑  收藏  举报