终于,到了第二十三种设计模式的最后一种模式,解释器模式,说真的到这里已经精疲力尽没有精力写了,只想快速的结尾,但是还是需要画下类图和实现一个例子的。一般主要应用在OOP开发中的编译器的开发中,所以适用面比较窄。
1、定义
给定一个语言,解释器模式可以定义出其文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
2、UML
哈抽象表达式单词写错,懒得改了:AbstractExpression
在解释器模式结构图中包含如下几个角色:
AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。
TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。
NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。
为什么说解释器模式也是通过中间类呢,按我自己的理解,解释器就是中间类,Context中的语言表示,通过解释器可以转变成我们理解的语言标识。
3、举例
通过上面的UML我们大概知道解释器模式的作用:对于一些固定文法构建一个解释句子的解释器。下面我们举一个例子,当然可能不是很准确。
我们有一个环境类Context,存储了两位数字,num1和num2。都是整数,这里有三种解释器。加法、减法、乘法解释器。不同的解释器会对环境类的两个数字做不同的解释,也就是操作,类图如下:
当然大家也许会问,为什么跟上面的UML类图不同,我这里只是举例,描述一些解释器的思想是对固定的文法也就是两个数字。构建一个解释语句来解释处理的一种思想。如果非得深入研究,那么大家可以去参考下编译原理。
源码如下
AbstractExpression
public interface AbstractExpression {
public int interpreter(Context context);
}
ADDExpression
/**
* 加法解释器
* @author suibibk.com
*/
public class ADDExpression implements AbstractExpression{
@Override
public int interpreter(Context context) {
return context.getNum1()+context.getNum2();
}
}
MinusExpression
/**
* 减法解释器
* @author suibibk.com
*/
public class MinusExpression implements AbstractExpression{
@Override
public int interpreter(Context context) {
return context.getNum1()-context.getNum2();
}
}
MultExpression
/**
* 乘法解释器
* @author suibibk.com
*/
public class MultExpression implements AbstractExpression{
@Override
public int interpreter(Context context) {
return context.getNum1()*context.getNum2();
}
}
Context
/**
* 环境变量,存放固定文法构建的句子
* @author suibibk.com
*/
public class Context {
private Integer num1;
private Integer num2;
public Context(Integer num1, Integer num2) {
super();
this.num1 = num1;
this.num2 = num2;
}
public Integer getNum1() {
return num1;
}
public Integer getNum2() {
return num2;
}
}
Client
public class Client {
public static void main(String[] args) {
//2-5+7
Integer result=new ADDExpression().interpreter(
new Context(new MinusExpression().interpreter(new Context(2, 5)), 7));
System.out.println(result);
}
}
运行client,毫无疑问,答案为4。
4、优缺点
优点
解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的非终结符表达式就可以了,若扩展语法,则只要增加非终结符类就可以了。
缺点
解释器模式会引起类膨胀,每个语法都要产生一个非终结符表达式,语法规则比较复杂时,可能产生大量的类文件,难以维护。
解释器模式采用递归调用方法,它导致调试非常复杂。
解释器由于使用了大量的循环和递归,所以当用于解析复杂、冗长的语法时,效率是难以忍受的
5、适用场景
在以下情况下可以考虑使用解释器模式:
可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
一些重复出现的问题可以用一种简单的语言来进行表达。
一个语言的文法较为简单。
执行效率不是关键问题。【注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。】
总结
解释器模式可利用的场景是在是太小了。我们理解就好,以后有机会再深入了解。到此23中设计模式的博文笔记已经做完,大呼一口气,不过以后当然还有随时的优化和修改,毕竟还有很多不足的地方,并且设计模式这个标签下以后会继续总结各种设计模式的实例,以及模式组合使用的情况。