设计模式之十四——解释器模式

原文传送门

1 介绍

解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。

1.1 什么是解释器模式

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

1.2 解决了什么问题

这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

2 原理

  • 参与者
    • AbstractExpression——抽象解释器。具体的解释任务由各个实现类完成,具体的解释器分别由TerminalExpression和Non-terminalExpression完成。
    • TerminalExpression——终结符表达式。实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。具体到我们例子就是VarExpression类,表达式中的每个终结符都在栈中产生了一个VarExpression对象。
    • NonterminalExpression——非终结符表达式。文法中的每条规则对应于一个非终结表达式,具体到我们的例子就是加减法规则分别对应到AddExpression和SubExpression两个类。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
    • Context——环境角色。具体到我们的例子中是采用HashMap代替。

2.1 uml图

解释器模式的通用类图

2.2 代码示例

Expression代码示例

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

TerminalExpression代码示例

public class TerminalExpression extends Expression {
     //通常终结符表达式只有一个,但是有多个对象
     public Object interpreter(Context ctx) {
             return null;
     }
}

NonterminalExpression代码示例

public class NonterminalExpression extends Expression {
     //每个非终结符表达式都会对其他表达式产生依赖
     public NonterminalExpression(Expression... expression){
     }

     public Object interpreter(Context ctx) {
             //进行文法处理
             return null;
     }
}
}

调用示例

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

2.3 优缺点

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

  • 缺点:

    1. 可利用场景比较少。
    2. 对于复杂的文法比较难维护。
    3. 解释器模式会引起类膨胀。
    4. 解释器模式采用递归调用方法。

3 适用场景

  1. 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  2. 一些重复出现的问题可以用一种简单的语言来进行表达。
  3. 一个简单语法需要解释的场景。

5 总结

解释器模式(Interpreter Pattern)是一种按照规定语法进行解析的方案,在现在项目中使用较少。
尽量不要在重要的模块中使用解释器模式,否则维护会是一个很大的问题。在项目中可以使用shell、JRuby、Groovy等脚本语言来代替解释器模式,弥补Java编译型语言的不足。我们在一个银行的分析型项目中就采用JRuby进行运算处理,避免使用解释器模式的四则运算,效率和性能各方面表现良好。


参考书籍及文章
1.《Java与模式》,电子工业出版社,阎宏

  1. 《大话设计模式》,清华大学出版社,程杰
  2. 《设计模式——可复用面向对象软件的基础》,机械工业出版社,Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides
  3. 《Head First 设计模式(中文版)》,中国电力出版社
  4. 《图说设计模式》,https://design-patterns.readthedocs.io/zh_CN/latest/index.html
  5. 《设计模式之禅》,https://www.kancloud.cn/sstd521/design

你可能感兴趣的:(设计模式之十四——解释器模式)