设计模式的艺术 行为型模式之解释器模式
前言
目前计算器编程语言有好几百种,但是有时候人们还是希望能用一些简单的语言表达实现一些特定的操作,比如输入一个文件,它就可以按照预定的格式进行解释,从而实现相应的功能。
在现实的开发中,这些简单的自定义语言可以通过现有的编程语言来设计,如果所基于的编程语言是面向对象语言,此时可以使用解释器模式来实现自定义语言
什么是解释器模式 Interpreter Pattern
定义一个语言的方法,并且建立一个解释器来解释该语言中的句子,这里的"语言"是指使用规定和语言的代码。解释器模式是一种对象行为型模式
解释器模式的优点
(1)、易于改变和扩展文法,由于解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制改变和扩展文法。
(2)、每一条文法规则都可以表示一个类,因此可以方便地实现一个简单的语言。
(3)、实现文法比较容易,在抽象语法树中每一个表示式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码
(4)、增加新的解释表达式比较方便,如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合开闭原则
解释器模式的缺点
(1)、对于复杂文法难以维护,在解释器模式中,每一个规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数会急剧增加,导致系统难以维护和管理,此时可以考虑使用语法分析程序等方式来取代解释器模式
(2)、执行效率低。由于在解释器模式总使用了大量的循环和递归调用,因此在解释器较为复杂的句子时速度很慢,而且代码调试过程也比较麻烦
解释器模式适用的场景
(1)、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
(2)、一些重复出现的问题可以用一种简单的语言来进行表达
(3)、一个语言的中文法较为简单
(4)、当执行效率不是关键问题时(毕竟解释器模式的执行效率并不高)
解释器模式的具体实现
目录结构(模拟机器人指令)
抽象基类
//本实例对机器人控制指令的输出结果进行模拟,将英文指令翻译为中文指令,实际情况是调用 //不同的控制程序进行机器人的控制,包括对移动方向、方式和距离的控制等 public abstract class AbstractNode { public abstract String interpret(); }
具体类
package com.company.node; //动作解释:终结符表达式 public class ActionNode extends AbstractNode { private String action; public ActionNode(String action) { this.action = action; } @Override //动作移动方式表示式的解释操作 public String interpret() { if(action.equalsIgnoreCase("move")){ return "移动"; }else if(action.equalsIgnoreCase("run")){ return "快速移动"; }else { return "无效指令"; } } }
package com.company.node; import com.company.node.AbstractNode; //And解释:非终结符表达式 public class AndNode extends AbstractNode { private AbstractNode left; //And的左表达式 private AbstractNode right; //ANd的右表达式 public AndNode(AbstractNode left, AbstractNode right) { this.left = left; this.right = right; } @Override //And表达式解释操作 public String interpret() { return left.interpret()+"再"+right.interpret(); } }
package com.company.node; import com.company.node.AbstractNode; //方向解释:终结符表达式 public class DirectionNode extends AbstractNode { private String direction; public DirectionNode(String direction) { this.direction = direction; } @Override //方向表达式的解释操作 public String interpret() { 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.company.node; import com.company.node.AbstractNode; //距离解释:终结符表达式 public class DistanceNode extends AbstractNode { private String distance; public DistanceNode(String distance) { this.distance = distance; } @Override //距离表达式的解释操作 public String interpret() { return this.distance; } }
package com.company.node; import com.company.node.AbstractNode; //简答句子解释:非终结符表达式 public class SentCeNode extends AbstractNode { private AbstractNode direction; private AbstractNode action; private AbstractNode distance; public SentCeNode(AbstractNode direction, AbstractNode action, AbstractNode distance) { this.direction = direction; this.action = action; this.distance = distance; } @Override //简单句子的解释操作 public String interpret() { return direction.interpret()+action.interpret()+distance.interpret(); } }
指令处理工具类
package com.company; import com.company.node.*; import java.util.Stack; //指令处理类:工具类 public class InstructionHandler { private AbstractNode node; public void handle(String instruction){ AbstractNode left=null,right=null; AbstractNode direction=null,action=null,distance=null; Stack stack=new Stack(); //声明一个栈对象用于储存抽象语法树 String[]words=instruction.split(" "); //以空格分隔指定字符串 for(int i=0;i<words.length;i++){ //本实例采用栈的方式类处理指令,如果遇到"and",则将其后的3个单词作为3个终结符 //表达式连成一个一个简单的句子SentceNode作为"and"的右表达式,而将从栈顶弹出的表达式 //作为"and"的左表达式,最后将新的"and"表达式压入栈中。 if(words[i].equalsIgnoreCase("and")){ left=(AbstractNode) stack.pop(); //弹出栈顶表示式作为左表达式 String word1=words[++i]; direction=new DirectionNode(word1); String word2=words[++i]; action=new ActionNode(word2); String word3=words[++i]; distance=new DistanceNode(word3); right=new SentCeNode(direction,action,distance); //右表达式 stack.push(new AndNode(left,right)); //将新表达式压入栈中 } //如果是从头开始进行解释,则将前三个单词组成一个简单的句子SentenceNode并将 //该句子压入栈中 else { String word1=words[i]; direction=new DistanceNode(word1); String word2=words[++i]; action=new ActionNode(word2); String word3=words[++i]; distance=new DistanceNode(word3); left=new SentCeNode(direction,action,distance); stack.push(left); } } this.node=(AbstractNode) stack.pop(); //将全部表达式从栈中弹出 } public String output(){ String result=node.interpret(); //解释表达式 return result; } }
客户端测试类
package com.company; public class Client { public static void main(String[] args) { String instruction ="up move 5 and down run 10 and left move 5"; InstructionHandler handler = new InstructionHandler(); handler.handle(instruction); String outString; outString = handler.output(); System.out.println(outString); } }