简介
解释器模式(Interpreter Pattern)是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。是一种按照规定的语法(文法)进行解析的模式,属于行为型模式。
比如编译器可以将源码编译解析为机器码,让CPU能进行识别并运行。解释器模式的作用其实与编译器一样,都是将一些固定的文法(即语法)进行解析,构建出一个解析句子的解释器。简单理解,解释器是一个简单语法分析工具,它可以识别句子语义,分离终结符号和非终结符号,提取出需要的信息,让我们能针对不同的信息做出相应的处理。其核心思想是识别文法,构建解释。
解释器模式的应用场景
1、音乐简谱
2、福尔摩斯密码
对于一些固定文法构建一个解释句子的解释器。解释器模式适用于以下应用场景:
1、一些重复出现的问题可以用一种简单的语言来进行表达;
2、一些简单语法需要解释的场景。
解释器模式的通用UML类图:
从UML类图中,我们可以看到,解释器模式主要包含四种角色:
抽象表达式(Expression):负责定义一个解释方法interpret,交由具体子类具体解析;
终结符表达式(TerminalExpression):实现文法中与终结符有关的解释操作,文法中的每一个终结符都有一个具体终结表达式与之对应。比如R = R1 + R2,R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符(R1,R2);
非终结符表达式(NonterminalExpression):实现文法中与终结符有关的解释操作。文法中的每条规则都对应与一个非终结符表达式。非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R = R1 + R2中,“+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式;
上下文环境类(Context):包含解释器之外的全局信息。它的任务一般是用来存放文法中各个终结符所对应的具体值,比如R = R1 + R2,给R1赋值100,给R2赋值200,这些信息需要存放到环境中。
解释器在源码中的体现
1、JDK源码中的Pattern对正则表达式的编译和解析
public final class Pattern implements java.io.Serializable {
...
private Pattern(String p, int f) {
pattern = p;
flags = f;
// to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
if ((flags & UNICODE_CHARACTER_CLASS) != 0)
flags |= UNICODE_CASE;
// Reset group index count
capturingGroupCount = 1;
localCount = 0;
if (pattern.length() > 0) {
try {
compile();
} catch (StackOverflowError soe) {
throw error("Stack overflow during pattern compilation");
}
} else {
root = new Start(lastAccept);
matchRoot = lastAccept;
}
}
...
public static Pattern compile(String regex) {
return new Pattern(regex, 0);
}
public static Pattern compile(String regex, int flags) {
return new Pattern(regex, flags);
}
}
2、Spring中的ExpressionParser
接口
public interface ExpressionParser {
Expression parseExpression(String expressionString) throws ParseException;
Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}
解释器模式的优缺点
优点:
1、扩展性强:在解释器模式中由于语法是由很多类表示的,当语法规则更改时,只需修改相应的非终结符表达式即可;若扩展语法时,只需添加相应非终结符类即可;
2、增加了新的解释表达式的方式;
3、易于实现文法:解释器模式对应的文法应当是比较简单且易于实现的,过于复杂的语法并不适合使用解释器模式。
缺点:
1、语法规则复杂时,会引起类膨胀:解释器模式每个语法都要产生一个非终结符表达式,当语法规则比较复杂时,就会产生大量的解释类,增加系统维护困难;
2、执行效率比较低:解释器模式采用递归调用方法,每个非终结符表达式只关心自己有关的表达式,每个表达式需要知道最终的结果,因此完整表达式的最终结果是通过从后往前递归调用的方式获取得到。当完整表达式层次较深时,解释效率下降,且出错时调试困难,因为递归迭代层级太深。