个人随笔
目录
二十三、行为型-通过中间类-解释器(Interpreter)模式
2020-09-09 21:49:50

终于,到了第二十三种设计模式的最后一种模式,解释器模式,说真的到这里已经精疲力尽没有精力写了,只想快速的结尾,但是还是需要画下类图和实现一个例子的。一般主要应用在OOP开发中的编译器的开发中,所以适用面比较窄。

1、定义

给定一个语言,解释器模式可以定义出其文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

2、UML


哈抽象表达式单词写错,懒得改了:AbstractExpression
在解释器模式结构图中包含如下几个角色:

  1. AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。
  2. TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。
  3. NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
  4. Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。

为什么说解释器模式也是通过中间类呢,按我自己的理解,解释器就是中间类,Context中的语言表示,通过解释器可以转变成我们理解的语言标识。

3、举例

通过上面的UML我们大概知道解释器模式的作用:对于一些固定文法构建一个解释句子的解释器。下面我们举一个例子,当然可能不是很准确。
我们有一个环境类Context,存储了两位数字,num1和num2。都是整数,这里有三种解释器。加法、减法、乘法解释器。不同的解释器会对环境类的两个数字做不同的解释,也就是操作,类图如下:

当然大家也许会问,为什么跟上面的UML类图不同,我这里只是举例,描述一些解释器的思想是对固定的文法也就是两个数字。构建一个解释语句来解释处理的一种思想。如果非得深入研究,那么大家可以去参考下编译原理。
源码如下

AbstractExpression
  1. public interface AbstractExpression {
  2. public int interpreter(Context context);
  3. }
ADDExpression
  1. /**
  2. * 加法解释器
  3. * @author suibibk.com
  4. */
  5. public class ADDExpression implements AbstractExpression{
  6. @Override
  7. public int interpreter(Context context) {
  8. return context.getNum1()+context.getNum2();
  9. }
  10. }
MinusExpression
  1. /**
  2. * 减法解释器
  3. * @author suibibk.com
  4. */
  5. public class MinusExpression implements AbstractExpression{
  6. @Override
  7. public int interpreter(Context context) {
  8. return context.getNum1()-context.getNum2();
  9. }
  10. }
MultExpression
  1. /**
  2. * 乘法解释器
  3. * @author suibibk.com
  4. */
  5. public class MultExpression implements AbstractExpression{
  6. @Override
  7. public int interpreter(Context context) {
  8. return context.getNum1()*context.getNum2();
  9. }
  10. }
Context
  1. /**
  2. * 环境变量,存放固定文法构建的句子
  3. * @author suibibk.com
  4. */
  5. public class Context {
  6. private Integer num1;
  7. private Integer num2;
  8. public Context(Integer num1, Integer num2) {
  9. super();
  10. this.num1 = num1;
  11. this.num2 = num2;
  12. }
  13. public Integer getNum1() {
  14. return num1;
  15. }
  16. public Integer getNum2() {
  17. return num2;
  18. }
  19. }
Client
  1. public class Client {
  2. public static void main(String[] args) {
  3. //2-5+7
  4. Integer result=new ADDExpression().interpreter(
  5. new Context(new MinusExpression().interpreter(new Context(2, 5)), 7));
  6. System.out.println(result);
  7. }
  8. }

运行client,毫无疑问,答案为4。

4、优缺点

优点

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

缺点

  1. 解释器模式会引起类膨胀,每个语法都要产生一个非终结符表达式,语法规则比较复杂时,可能产生大量的类文件,难以维护。
  2. 解释器模式采用递归调用方法,它导致调试非常复杂。
  3. 解释器由于使用了大量的循环和递归,所以当用于解析复杂、冗长的语法时,效率是难以忍受的

5、适用场景

在以下情况下可以考虑使用解释器模式:

  1. 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  2. 一些重复出现的问题可以用一种简单的语言来进行表达。
  3. 一个语言的文法较为简单。
  4. 执行效率不是关键问题。【注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。】

总结

解释器模式可利用的场景是在是太小了。我们理解就好,以后有机会再深入了解。到此23中设计模式的博文笔记已经做完,大呼一口气,不过以后当然还有随时的优化和修改,毕竟还有很多不足的地方,并且设计模式这个标签下以后会继续总结各种设计模式的实例,以及模式组合使用的情况。

 148

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2