一、定义
nterpreter(解释器)模式是一种特殊的设计模式,它建立一个解释器(Interpreter),对于特定的计算机程序设计语言,用来解释预先定义的文法。简单地说,Interpreter模式是一种简单的语法解释器构架。
解释器模式属于行为模式,Gof是这样定义的: 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
二、角色
- 抽象表达式(Expression)角色: 声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个interpret()方法,称做解释操作。
- 终结符表达式(Terminal Expression)角色: 实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
- 非终结符表达式(Nonterminal Expression)角色: 文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+"就是非终结符,解析“+”的解释器就是一个非终结符表达式。
- 环境(Context)角色: 这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。
三、场景展示
类图如下:
定义抽象类
package com.ssy.wlj.interpreter;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public abstract class AbstractNode {
public abstract String interpret();
}
定义抽象类的实现类
package com.ssy.wlj.interpreter;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public class ActionNode extends AbstractNode {
private String action;
public ActionNode(String a) {
// TODO Auto-generated constructor stub
this.action=a;
}
@Override
public String interpret() {
// TODO Auto-generated method stub
if(action.equalsIgnoreCase("move")) {
return "移动";
}else if(action.equalsIgnoreCase("run")) {
return "奔跑";
}else {
return "无效指令";
}
}
}
package com.ssy.wlj.interpreter;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public class AndNode extends AbstractNode {
private AbstractNode left; //左表达式
private AbstractNode right; //右表达式
public AndNode(AbstractNode l,AbstractNode r) {
// TODO Auto-generated constructor stub
this.left=l;
this.right=r;
}
@Override
public String interpret() {
// TODO Auto-generated method stub
return left.interpret()+"再"+right.interpret();
}
}
package com.ssy.wlj.interpreter;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public class DirectionNode extends AbstractNode {
private String direction;
public DirectionNode(String dir) {
// TODO Auto-generated constructor stub
this.direction=dir;
}
@Override
public String interpret() {
// TODO Auto-generated method stub
if(direction.equalsIgnoreCase("up")) {
return "向上";
}else if(direction.equalsIgnoreCase("down")) {
return "向下";
}else if(direction.equalsIgnoreCase("left")) {
return "向左";
}else if(direction.equalsIgnoreCase("right")) {
return "向右";
}else {
return "无效指令";
}
}
}
package com.ssy.wlj.interpreter;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public class DistanceNode extends AbstractNode{
private String distance;
public DistanceNode(String d) {
// TODO Auto-generated constructor stub
this.distance=d;
}
@Override
public String interpret() {
// TODO Auto-generated method stub
return distance;
}
}
package com.ssy.wlj.interpreter;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public class SentenceNode extends AbstractNode{
private AbstractNode direction;
private AbstractNode action;
private AbstractNode distanc;
public SentenceNode(AbstractNode direc,AbstractNode a,AbstractNode d) {
// TODO Auto-generated constructor stub
this.direction=direc;
this.action=a;
this.distanc=d;
}
@Override
public String interpret() {
// TODO Auto-generated method stub
return direction.interpret()+action.interpret()+distanc.interpret();
}
}
定义Handler
package com.ssy.wlj.interpreter;
import java.util.Stack;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public class InstructionHandler {
private AbstractNode node;
public void Handle(String instruction) {
//用栈来保存语法树。
AbstractNode left=null,right=null;
AbstractNode direction=null,action=null,distance=null;
Stack<AbstractNode> stack = new Stack<AbstractNode>();
//用空格分隔指令
String[] word = instruction.split(" ");
//循环
for(int i=0;i<word.length;i++) {
if(word[i].equalsIgnoreCase("and")) {
left = (AbstractNode)stack.pop();
String wordl=word[++i];
direction = new DirectionNode(wordl);
String word2 = word[++i];
action = new ActionNode(word2);
String word3 =word[++i];
distance = new DistanceNode(word3);
right = new SentenceNode(direction, action, distance);
}else {
String word1 = word[i];
direction = new DirectionNode(word1);
String word2 = word[++i];
action = new ActionNode(word2);
String word3 = word[++i];
distance = new DistanceNode(word3);
left= new SentenceNode(direction, action, distance);
stack.push(left);
}
}
this.node=(AbstractNode)stack.pop();
}
public String output() {
String result = node.interpret();
return result;
}
}
编写客户端程序:
package com.ssy.wlj.interpreter;
/**
* 类说明:
* @author happy
* @since 2019年5月25日
*
*/
public class Client {
public static void main(String[] args) {
String instruction ="down run 10 and left move 20";
InstructionHandler iHandler = new InstructionHandler();
iHandler.Handle(instruction);
String outString ;
outString =iHandler.output();
System.out.println(outString);
}
}
解释器模式的优缺点及使用场景
优点:
- 易于改变和扩展文法,由于在解释器模式中使用类表示语言的文法规则,因此可以通过继承等机制来改变和扩张文法。
- 每一条文法规则都可以表示为一个类,因此可以方便地实现每一个简单的语言。
- 实现文法比较容易。
缺点:
- 对于复杂文法难以维护,再解释模式下每一条规则至少定义一个类,因此如果太复杂无法处理。
- 执行效率低,由于大量使用了循环和递归。因此再解释很复杂的句子时速度很慢
使用场景:
- 可以将一个需要解释执行的语言中的句子表示为一个抽象树。
- 一些重复出现的问题可以用简单的语言进行表达。
- 执行效率不是关键问题。