解释器模式提供了一种评估计算语言语法或表达式的方法。 这种类型的模式属于行为模式。 这种设计模式涉及实现一个表达式接口,它告诉解释一个指定的上下文。 此模式用于SQL解析,符号处理引擎等。node
解释器模式包含如下主要角色。设计模式
//环境类:用于存储和操做须要解释的语句,在本实例中每个须要解释的单词能够称为一个动做标记(Action Token)或命令 class Context { private StringTokenizer tokenizer; //StringTokenizer类,用于将字符串分解为更小的字符串标记(Token),默认状况下以空格做为分隔符 private String currentToken; //当前字符串标记 public Context(String text) { tokenizer = new StringTokenizer(text); //经过传入的指令字符串建立StringTokenizer对象 nextToken(); } //返回下一个标记 public String nextToken() { if (tokenizer.hasMoreTokens()) { currentToken = tokenizer.nextToken(); } else { currentToken = null; } return currentToken; } //返回当前的标记 public String currentToken() { return currentToken; } //跳过一个标记 public void skipToken(String token) { if (!token.equals(currentToken)) { System.err.println("错误提示:" + currentToken + "解释错误!"); } nextToken(); } //若是当前的标记是一个数字,则返回对应的数值 public int currentNumber() { int number = 0; try { number = Integer.parseInt(currentToken); //将字符串转换为整数 } catch (NumberFormatException e) { System.err.println("错误提示:" + e); } return number; } } //抽象节点类:抽象表达式 abstract class Node { public abstract void interpret(Context text); //声明一个方法用于解释语句 public abstract void execute(); //声明一个方法用于执行标记对应的命令 } //表达式节点类:非终结符表达式 class ExpressionNode extends Node { private ArrayList<Node> list = new ArrayList<Node>(); //定义一个集合用于存储多条命令 public void interpret(Context context) { //循环处理Context中的标记 while (true) { //若是已经没有任何标记,则退出解释 if (context.currentToken() == null) { break; } //若是标记为END,则不解释END并结束本次解释过程,能够继续以后的解释 else if (context.currentToken().equals("END")) { context.skipToken("END"); break; } //若是为其余标记,则解释标记并将其加入命令集合 else { Node commandNode = new CommandNode(); commandNode.interpret(context); list.add(commandNode); } } } //循环执行命令集合中的每一条命令 public void execute() { Iterator iterator = list.iterator(); while (iterator.hasNext()) { ((Node) iterator.next()).execute(); } } } //语句命令节点类:非终结符表达式 class CommandNode extends Node { private Node node; public void interpret(Context context) { //处理LOOP循环命令 if (context.currentToken().equals("LOOP")) { node = new LoopCommandNode(); node.interpret(context); } //处理其余基本命令 else { node = new PrimitiveCommandNode(); node.interpret(context); } } public void execute() { node.execute(); } } //循环命令节点类:非终结符表达式 class LoopCommandNode extends Node { private int number; //循环次数 private Node commandNode; //循环语句中的表达式 //解释循环命令 public void interpret(Context context) { context.skipToken("LOOP"); number = context.currentNumber(); context.nextToken(); commandNode = new ExpressionNode(); //循环语句中的表达式 commandNode.interpret(context); } public void execute() { for (int i = 0; i < number; i++) commandNode.execute(); } } //基本命令节点类:终结符表达式 class PrimitiveCommandNode extends Node { private String name; private String text; //解释基本命令 public void interpret(Context context) { name = context.currentToken(); context.skipToken(name); if (!name.equals("PRINT") && !name.equals("BREAK") && !name.equals("SPACE")) { System.err.println("非法命令!"); } if (name.equals("PRINT")) { text = context.currentToken(); context.nextToken(); } } public void execute() { if (name.equals("PRINT")) System.out.print(text); else if (name.equals("SPACE")) System.out.print(" "); else if (name.equals("BREAK")) System.out.println(); } }
客户端测试代码工具
class Client { public static void main(String[] args) { String text = "LOOP 2 PRINT 杨过 SPACE SPACE PRINT 小龙女 BREAK END PRINT 郭靖 SPACE SPACE PRINT 黄蓉"; Context context = new Context(text); Node node = new ExpressionNode(); node.interpret(context); node.execute(); } }
在本实例代码中,环境类 Context 相似一个工具类,它提供了用于处理指令的方法,如 nextToken()、currentToken()、skipToken() 等,同时它存储了须要解释的指令并记录了每一次解释的当前标记(Token),而具体的解释过程交给表达式解释器类来处理。咱们还能够将各类解释器类包含的公共方法移至环境类中,更好地实现这些方法的重用和扩展。oop
优势:测试
解释器是一个简单语法分析工具,它最显著的优势就是扩展性,修改语法规则只要修改相应的非终结符表达式就能够了,若扩展语法,则只要增长非终结符类就能够了。spa
缺点:设计
每一个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了很是多的麻烦。调试
解释器模式采用递归调用方法,若是要排查一个语法错误,要一个一个断点的调试下去,会很麻烦。code
解释器模式使用了大量的循环和递归,特别是用于解析复杂、冗长的语法时,效率会很低。orm
……更多设计模式的内容,能够访问Refactoring.Guru