解释器模式

场景引入:解释器模式用于描述如何构成一个简单的语言解释器,主要应用于使用面向对象语言开发的解释器的设计。当需要开发一个新的语言的时候可以考虑使用解释器模式

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

文法规则和抽象语法树

本文以加/减法解释器为例,每一个输入表达式(例如1+2+3-4+1)都是包含了3个语言单位,可以使用以下文法规则来定义:

expression :: = value | operation
operation :: = expression '+' expression | expression '-' expression
value :: = an integer        //一个整数值

该文法规则包含3条语句,第一条表示表达式的组成方式,其中value和operation是后面两个语言单位的定义,每一条语句所定义的字符串(如operation和value)称为语言构造成分或语言单位,符号“::=”是定义为的意思,其左边的语言单位通过右边来进行说明和定义,语言单位对应终结符表达式和非终结符表达式。例如本规则中的operation是非终结符表达式,它的组成元素仍可以是表达式,可以进一步分解,而value是终结符表达式,它的组成元素是最基本的语言单位,不能再进行分解。

抽象语法树可以直观的表示语言的构成,每一棵抽象语法树对应一个语言实例。例如加法/减法表达式语言中的语句“1+2+3-4+1”可以通过如图所示的抽象语法树来表示:

解释器模式结构

解释器模式包含以下4个角色:

(1)AbstractExpression(抽象表达式):在抽象表达式中声明了抽象解释操作,它是所有终结符和非终结符表达式的父类

(2)TerminalExpression(终结符表达式):它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例

(3)NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式完成

(4)Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通过它临时存储了需要解释的语句

 解释器模式应用实例

1. 实例说明

某公司要开发一套简单的机器人控制程序,控制程序中包含一些简单的英文控制指令,每一个指令对应一个表达式,该表达式可以是简单的表达式也可以是复合表达式,每一个简单的表达式由移动方向(上:up、下:down、左:left、右:right),移动方式(移动:move、快速移动:run),移动距离(一个正整数),两个表达式可以通过与(and)连接形成复合表达式。控制指令示例:“down run 10 and left move 5”,则“向下快速移动10个单位再向左移动5个单位”;输入“up move 10”,则“向上移动10个单位”

2. 实例分析及类图

根据上述的需求描述用形式化语言表达的文法规则如下:

expression ::= direction action distance | composite        //表达式
composite ::= expression 'and' expression               //复合表达式
direction ::= 'up' | 'down' | 'left' | 'right'             //移动方向
action ::= 'move' | 'run'                                  //移动方式
distance ::= an integer                                    //移动距离

3. 代码实例

1 package designpatterns.interpreter;
2 
3 public abstract class AbstractNode {
4     public abstract String interpret();
5 }
 1 package designpatterns.interpreter;
 2 
 3 public class AndNode extends AbstractNode {
 4     private AbstractNode left;        //And的左表达式
 5     private AbstractNode right;        //And的右表达式
 6     
 7     public AndNode(AbstractNode left, AbstractNode right) {
 8         this.left = left;
 9         this.right = right;
10     }
11 
12     @Override
13     public String interpret() {
14         return left.interpret() + "再" + right.interpret();
15     }    
16 }
 1 package designpatterns.interpreter;
 2 
 3 public class SentenceNode extends AbstractNode {
 4     private AbstractNode direction;
 5     private AbstractNode action;
 6     private AbstractNode distance;
 7 
 8     public SentenceNode(AbstractNode direction, AbstractNode action, AbstractNode distance) {
 9         super();
10         this.direction = direction;
11         this.action = action;
12         this.distance = distance;
13     }
14 
15     @Override
16     public String interpret() {
17         return direction.interpret() + action.interpret() + distance.interpret();
18     }
19 
20 }
 1 package designpatterns.interpreter;
 2 
 3 public class DirectionNode extends AbstractNode {
 4     private String direction;
 5 
 6     public DirectionNode(String direction) {
 7         super();
 8         this.direction = direction;
 9     }
10 
11     @Override
12     public String interpret() {
13         if(direction.equalsIgnoreCase("up")){
14             return "向上";
15         }
16         else if(direction.equalsIgnoreCase("down")) {
17             return "向下";
18         }
19         else if(direction.equalsIgnoreCase("left")) {
20             return "向左";
21         }
22         else if(direction.equalsIgnoreCase("right")) {
23             return "向右";
24         }
25         else{
26             return "无效指令";
27         }
28     }
29 }
 1 package designpatterns.interpreter;
 2 
 3 public class ActionNode extends AbstractNode {
 4     private String action;
 5     
 6     public ActionNode(String action) {
 7         super();
 8         this.action = action;
 9     }
10     
11     @Override
12     public String interpret() {
13         if(action.equalsIgnoreCase("move")) {
14             return "移动";
15         }
16         else if(action.equalsIgnoreCase("run")){
17             return "快速移动";
18         }
19         else{
20             return "无效指令";
21         }
22     }
23 }
 1 package designpatterns.interpreter;
 2 
 3 public class DistanceNode extends AbstractNode {
 4     private String distance;
 5     
 6     public DistanceNode(String distance) {
 7         super();
 8         this.distance = distance;
 9     }
10 
11     @Override
12     public String interpret() {
13         return this.distance;
14     }
15 }
 1 package designpatterns.interpreter;
 2 
 3 import java.util.Stack;
 4 
 5 public class InstructionHandler {
 6     private AbstractNode node;
 7     
 8     public void handle(String instruction){
 9         AbstractNode left = null,right = null;
10         AbstractNode action = null,direction = null,distance = null;
11         
12         //声明一个栈对象用于存储抽象语法树
13         Stack<AbstractNode> stack = new Stack<AbstractNode>();
14         //以空格分割指令字符串
15         String[] words = instruction.split(" ");
16         for(int i = 0;i < words.length;i++) {
17             /**
18              * 本实例采用栈的方式处理指令,如果遇到and,将其后的3个单词作为3个终结
19              * 表达式连成一个简单句子SentenceNode作为and的右表达式,而将从栈顶
20              * 弹出的表达式作为and的左表达式,最后将新的and表达式压入栈中
21              */
22             if(words[i].equalsIgnoreCase("and")) {
23                 left = (AbstractNode)stack.pop();    //弹出栈顶表达式作为左表达式
24                 String word1 = words[++i];
25                 direction = new DirectionNode(word1);
26                 String word2 = words[++i];
27                 action = new ActionNode(word2);
28                 String word3 = words[++i];
29                 distance = new DistanceNode(word3);
30                 
31                 right = new SentenceNode(direction, action, distance);
32                 stack.push(new AndNode(left,right));    //将新表达式压入栈中
33             }
34             else{
35                 String word1 = words[i];
36                 direction = new DirectionNode(word1);
37                 String word2 = words[++i];
38                 action = new ActionNode(word2);
39                 String word3 = words[++i];
40                 distance = new DistanceNode(word3);
41                 left = new SentenceNode(direction, action, distance);
42                 stack.push(left);
43             }
44         }
45         this.node = (AbstractNode)stack.pop();        //将全部表达式从栈中弹出
46     }
47     
48     public String output(){
49         String result = node.interpret();            //解释表达式
50         return result;
51     }
52 }
 1 package designpatterns.interpreter;
 2 
 3 public class Client {
 4     public static void main(String[] args) {
 5         String instruction = "down run 10 and up move 20";
 6         InstructionHandler handler = new InstructionHandler();
 7         handler.handle(instruction);
 8         
 9         String outputString;
10         outputString = handler.output();
11         System.out.println(outputString);
12     }
13 }

4. 结果及分析

解释器模式优/缺与适用环境

1.解释器模式优点

(1)易于改变和扩展文法

(2)每一条文法规则都可以表示为一个类,因此可以方便的实现一个简单的语言

(3)实现文法较为容易

(4)增加新的解释表达式较为方便

2.解释器模式缺点

(1)对于复杂的文法难以维护

(2)执行效率低

3. 解释器模式的适用环境

(1)可以将一个需要解释执行的语言中的句子表达为一个抽象语法书

(2)一些重复出现的问题可以用一个简单的语言进行表达

(3)一个语言的文法比较简单

(4)执行效率不是关键问题

原文地址:https://www.cnblogs.com/remote/p/10718240.html