此次介绍另外一个行为模式,解释器模式,都说解释器模式用的少,其实只是咱们在平常的开发中用的少,可是一些开源框架中仍是能见到它的影子,例如:spring的spEL表达式在解析时就用到了解释器模式,以及mybatis在将SQL语句映射成对象时关系时、还有一些解析正则表达式和解析json等开源工具。html
解释器模式是指给定一个使用规定格式和语法的语言,而且创建一个解释器来解释该语言中的句子。解释器自己就是一种按照规定的语法进行解析的方案,可是整体来讲也是一种使用频率相对较低但学习难度较大的设计模式。正则表达式
由于解释器模式用到地方不太多,实在想不到举什么样的例子合适,因此就使用一个简单的来实现一个垒加的功能的例子吧。spring
具体过程以下:json
上下文环境类设计模式
@Getter @Setter public class Context { /** * 输入 */ private String input; /** * 结果 */ private int output; public Context(String input){ this.input = input; } @Override public String toString() { return input + "=" + output; } }
抽象表达式类mybatis
public abstract class Expression { Context context; /** * 解释一个给定的表达式 * @param context */ public abstract void interpret(Context context); }
垒加类框架
/** * 垒加1 */ public class MinusExpression extends Expression { /** * 解释一个给定的表达式 * * @param context */ @Override public void interpret(Context context) { this.context = context; String input = context.getInput(); int in = Integer.valueOf(input); context.setOutput(in-1); } @Override public String toString() { return "--"+context.getInput()+"="+context.getOutput(); } }
垒减ide
/** * 垒减 */ public class PlusExpression extends Expression { /** * 解释一个给定的表达式 * * @param context */ @Override public void interpret(Context context) { this.context = context; String input = context.getInput(); int in = Integer.valueOf(input); context.setOutput(in+1); } @Override public String toString() { return "++"+context.getInput()+"="+context.getOutput(); } }
测试,使用工具
public class Client { public static void main(String[] args) { Context context = new Context("50"); Expression plus = new PlusExpression(); Expression minus = new MinusExpression(); //执行垒加 plus.interpret(context); System.out.println(plus.toString()); //垒减 minus.interpret(context); System.out.println(minus.toString()); } }
运行结果post
++50=51 --50=49
经过运算结果能够看出来,表达式经过解释后的结果,++50解释后结果是51,--50解释后结果是49。
解释器模式的结构图以下:
解释器类图上的各个角色说明:
Expression(抽象解释器):定义解释方法,具体的解释任务由各个实现类完成,具体的解释器分别由TerminalRxpression和NonterMinalExpression完成。抽象解释器对应上面例子中的Expression类
TerminalExpression(终结符表达式):实现与文法中的元素相关的解释操做,一个解释器模式中只有一个终结符表达式,但有多个实例,对应不一样的终结符。上面的代码例子中的PlusExpression和MinusExpression都是这个角色。
NoteTerminalExpression(非终结符表达式):文法中的每条规则对应于一个非终结符表达式。非终结符表达式是根据逻辑的复杂度而增长,原则上每一个文法规则都对应一个非终结符表达式。因为上面举得例子比较简单,因此上面的例子中是没有这个角色的。
Context(环境角色):环境类又称为上下文类,它用于存储解释器以外的一些全局信息,一般它临时存储了须要解释的语句。也可使用集合用来存储要解释的内容。
一、易于改变和扩展文法。由于该模式使用类表示文法,因此可使用继承改变或扩展该文法。
二、每条文法规则均可以是一个类,因此能够很方便的实现一个简单的语言。
三、易于实现文法的定义。在抽象语法树中每个表达式节点类的实现方式都是类似的,这些类的代码编写都不会特别复杂,还能够经过一些工具自动生成节点类代码。
四、增长新的解释表达式较为方便。若是用户须要增长新的解释表达式只须要对应增长一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”。
一、对于复杂文法难以维护。在解释器模式中,每一条规则至少须要定义一个类,所以若是一个语言包含太多文法规则,类的个数将会急剧增长,致使系统难以管理和维护,此时能够考虑使用语法分析程序等方式来取代解释器模式。
二、执行效率较低。因为在解释器模式中使用了大量的循环和递归调用,所以在解释较为复杂的句子时其速度很慢,并且代码的调试过程也比较麻烦。
一、能够将一个须要解释执行的语言中的句子表示为一个抽象语法树。
三、一个语言的文法较为简单。
四、执行效率不是关键问题。【注:高效的解释器一般不是经过直接解释抽象语法树来实现的,而是须要将它们转换成其余形式,使用解释器模式的执行效率并不高。】
想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述。