什么是解释器模式
解释器模式是一种类行为型模式
解释器模式用于定义一个文法,通过解释器来解释为其中的代码。
解释器模式在开发中用的不多,通常应用于研发过程中。
比如说,我们优化出了一个精妙绝伦的文法,但是这个算法对于开发者来说很难应用,所以我们就需要将开发者的语句解释成文法。
核心结构
- Context。环境类,用于存储解释器之外的全局信息,通常用于存储需要解释的语句。
- AbstractExpression。抽象表达式,声明了解释方法。
- TerminalExpression。终结符表达式,是抽象表达式的子类,它实现了终结符相关联的解释方法,文法语句中每个终结符都是该类的子类,可以通过非终结符表达式组合成复杂的句子。
- NonterminalExpression。非终结符表达式,它同样实现了抽象表达式的解释方法,既可以继续包含终结符表达式,也可以包含非终结符表达式,因此解释方法一般通过简单算法、循环、递归方式完成。
类图展示
代码分析
解释器模式在我们的开发中不经常用到,但是在研发中,是非常常见的设计模式,比如说当我们需要设计一个计算器时,就需要把输入的实数解释成机器可以读懂的语言。
那我们就实现一个简单的计算器吧。
首先,创建环境类,告诉文法,我们要做什么:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——环境类
*/
public class Context {
private Map<String, Integer> values = new HashMap<String, Integer>();
public void put(String key, Integer value) {
values.put(key, value);
}
public Integer get(String key) {
if (values.containsKey(key)) {
return values.get(key);
}
return 0;
}
}
Context中,我们用一个HashMap来存储参数和对应的值。
接下来我们就应该创建核心类——抽象表达式:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——抽象表达式
*/
public abstract class Expression {
public abstract int interpreter(Context context);
}
根据前面的类图我们可知,表达式又分为终结表达式和非中介表达式。
所以我们先创建一个基本的——终结表达式:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——终结表达式
*/
public class ValueExpression extends Expression{
private Integer i;
public Integer getI() {
return i;
}
public void setI(Integer i) {
this.i = i;
}
public ValueExpression(Integer i) {
this.i = i;
}
@Override
public int interpreter(Context context) {
return this.i;
}
}
而在本次实例中,非终结表达式代表加、减、乘、除的运算。
首先我们本着抽象继承的思维,创建一个抽象父类——操作符表达式:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——抽象非终结表达式
*/
public abstract class OperationExpression extends Expression {
protected Expression left;
protected Expression right;
public OperationExpression() {
}
public OperationExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
}
接下来创建加、减、乘、除四个具体操作符表达式。
加法:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——非终结具体表达式
*/
public class AddOperationExpression extends OperationExpression {
public AddOperationExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(Context context) {
return this.left.interpreter(context) + this.right.interpreter(context);
}
}
减法:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——非终结具体表达式
*/
public class MinusOperationExpression extends OperationExpression {
public MinusOperationExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(Context context) {
return this.left.interpreter(context) - this.right.interpreter(context);
}
}
乘法:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——非终结具体表达式
*/
public class MultiplyOperationExpression extends OperationExpression {
public MultiplyOperationExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(Context context) {
return this.left.interpreter(context) * this.right.interpreter(context);
}
}
除法:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式——非终结具体表达式
*/
public class DivideOperationExpression extends OperationExpression {
public DivideOperationExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(Context context) {
return this.left.interpreter(context) / this.right.interpreter(context);
}
}
惯例,测试代码:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/6/22.
* 解释器模式测试
*/
public class InterpreterTest {
public static void main(String[] args) {
Context context = new Context();
context.put("a", 9);
context.put("b", 8);
context.put("c", 7);
context.put("d", 6);
context.put("e", 5);
// (9 + 8 - 7) * 6 / 5
Expression addOperationExpression = new AddOperationExpression(new ValueExpression(context.get("a")), new ValueExpression(context.get("b")));
Expression minusOperationExpression = new MinusOperationExpression(addOperationExpression, new ValueExpression(context.get("c")));
Expression multiplyOperationExpression = new MultiplyOperationExpression(minusOperationExpression, new ValueExpression(context.get("d")));
Expression divideOperationExpression = new DivideOperationExpression(multiplyOperationExpression, new ValueExpression(context.get("e")));
System.out.println(divideOperationExpression.interpreter(context));
}
}
模式总结
优点
- 易于改变和扩展文法,可以通过对抽象表达式的多种实现,创造更多的解释语法。
- 每一条文法规则代表一个类,可以方便地实现一个简单的语言。
- 符合开闭原则,复杂语法表达式可以通过添加、组合终结表达式和非终结表达式即可,无需变更已有具体表达式。
- 每个表达式都是类似的,可以利用工具批量生产。
缺点
- 对于复杂的文法,可能有较大的设计难度,同时可能会造成类的指数级别增长。
- 由于会使用大量的循环和递归调用,生成的算法的时间复杂度可能不尽如人意。
适用场景
- 核心文法,通过解释器模式方便开发者使用。
- 简单的文法。
- 忽略执行效率的文法。
- 重复出现的问题,酌情使用解释器模式进行解决。