一、定义
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); } }
解释器模式的优缺点及使用场景
优点:
- 易于改变和扩展文法,由于在解释器模式中使用类表示语言的文法规则,因此可以通过继承等机制来改变和扩张文法。
- 每一条文法规则都可以表示为一个类,因此可以方便地实现每一个简单的语言。
- 实现文法比较容易。
缺点:
- 对于复杂文法难以维护,再解释模式下每一条规则至少定义一个类,因此如果太复杂无法处理。
- 执行效率低,由于大量使用了循环和递归。因此再解释很复杂的句子时速度很慢
使用场景:
- 可以将一个需要解释执行的语言中的句子表示为一个抽象树。
- 一些重复出现的问题可以用简单的语言进行表达。
- 执行效率不是关键问题。