模式的定义

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

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

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

类型

行为类

模式的使用场景

  • 重复发生的问题可以使用解释器模式
  • 一个简单语法需要解释的场景

注意事项

尽量不要在重要的模块中使用解释器模块,否则维护会是一个很大的问题。
解释器模式在实际的系统开发中使用得非常少了,因为它会引起效率,性能和维护的问题。一般在大中型的框架型项目能够找到它的身影,如果你要使用它,可以虚拟一下Expression4J,MESP(Math Expression String Parser),Jep等开源的解释器工具包,功能都异常强大,而且非常容易使用,效率也还不错,实现大多数的数学运算完全没有问题,自己没有必要从头开始编写解释器。

优点

解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的非终结符表达式就可以了,若扩展语法,则只要增加非终结符类就可以。

缺点

  • 解释器模式会引起类膨胀
    每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。
  • 解释器模式采用递归调用方法,逻辑复杂,调试不方便
  • 由于大量使用循环和递归,效率问题要考虑

UML类图

设计模式之解释器模式--- Pattern Interpreter_设计模式

角色介绍

AbstractExpression—抽象解释器
具体的解释任务由各个实现类完成,具体解释器分别由TerminalExpression和NonterminalExpression完成。

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

NonterminalExpression—非终结符表达式
文法中的每条规则对应于一个非终结符表达式

Context—环境角色

模式的通用源码

Expression:

public abstract class Expression {
    //每个表达式必须有一个解析任务
    public abstract Object interpreter(Context context);
}

抽象表达式是生成语法集合(也叫做语法树)的关键,每个语法集合完成指定语法解析任务,它是通过递归调用的方式,最终由最小的语法单元进行解析完成。

TerminalExpression:

public class TerminalExpression extends Expression {
    //通常终结符表达式只有一个,但是有多个对象
    @Override
    public Object interpreter(Context context) {
        // TODO Auto-generated method stub
        return null;
    }
}

终结符表达式比较简单,主要是处理场景元素和数据的转换。

NonterminalExpression:

public class NonterminalExpression extends Expression {
    //每个非终结符表达式都会对其他表达式产生依赖
    public NonterminalExpression(Expression... expressions) {
        // TODO Auto-generated constructor stub
    }

    @Override
    public Object interpreter(Context context) {
        // TODO Auto-generated method stub
        //进行文法处理
        return null;
    }
}

每个非终结符表达式都代表一个文法规则,并且每个文法规则都只关心自己周边的文法规则的结果,因此这就产生了每个非终结符表达式调用自己周边的非终结符表达式,然后最终,最小的文法规则就是终结符表达式,终结符表达式的概念就是如此,不能够再参与比自己更小的方法运算了。

Client:

import java.util.Stack;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Context context = new Context();
        //通常定一个语法容器,容纳一个具体的表达式,通常ListArray,LinkedList,Stact靠等类型
        Stack<Expression> stack = null;
        for (;;) {
            //进行语法判断,并产生递归调用
        }
        //产生一个完整的语法树,由各个具体的语法分析进行解析
        Expression expression = stack.pop();
        //具体元素进入场景
        expression.interpreter(context);    
    }

}

参考资料

(1).设计模式之禅—第27章 解释器模式
(2)解释器模式
https://github.com/simple-android-framework/android_design_patterns_analysis