解释器模式(Interpreter Pattern)
-
优点
1、可扩展性好。
2、易于实现。 -
缺点
1、执行效率较低。模式通常使用大量循环和递归调用,解释复杂句子时,运行速度很慢。
2、会引起类膨胀。模式中每条规则至少需要定义一个类,语法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
3、应用的场景少。JAVA 中如果碰到可以用 expression4J 代替。 -
模式中主要角色
抽象表达式:定义一个抽象解释方法。
非终结表达式:实现语法中与非终结符有关的解释操作。
终结表达式:实现语法中与终结符有关的解释操作。
客户类:解析表达式。 -
例子:加减法的实现,类图如下:
-
代码实现
抽象表达式
public interface AbstractExpression {
double interpret();
}
非终结表达式
/**
* 加法解释器
*/
public class AddExpression implements AbstractExpression {
private AbstractExpression left;
private AbstractExpression right;
public AddExpression(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
@Override
public double interpret() {
return left.interpret() + right.interpret();
}
}
/**
* 减法解释器
*/
public class SubExpression implements AbstractExpression {
private AbstractExpression left;
private AbstractExpression right;
public SubExpression(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
@Override
public double interpret() {
return left.interpret() - right.interpret();
}
}
终结表达式
public class TerminalExpression implements AbstractExpression {
private String value;
public TerminalExpression(String value) {
this.value = value;
}
@Override
public double interpret() {
return Double.valueOf(value);
}
}
客户类
public class Client {
//声明一个stack栈存储并操作所有相关的解释器
private AbstractExpression mExpStack;
public Client(String expression) {
//定义两个临时变量
AbstractExpression exp1, exp2;
//根据空格分割表达式字符串
String[] elements = expression.split(" ");
//循环遍历元素
for (int i = 0; i < elements.length; i++) {
switch (elements[i].charAt(0)){
case '+':
exp1 = mExpStack;
exp2 = new TerminalExpression(elements[++i]);
mExpStack = new AddExpression(exp1,exp2);
break;
case '-':
exp1 = mExpStack;
exp2 = new TerminalExpression(elements[++i]);
mExpStack = new SubExpression(exp1,exp2);
break;
default:
mExpStack = new TerminalExpression(elements[i]);
break;
}
}
}
public double calculate(){
return mExpStack.interpret();
}
}
测试
public class Test {
public static void main(String[] args) {
String expression = "10 + 3 + 1 + 2.6 - 12 - 1 + 13 + 13";
Client c = new Client(expression);
System.out.println(expression + " = " + c.calculate());
}
}
// 运行结果
10 + 3 + 1 + 2.6 - 12 - 1 + 13 + 13 = 29.6
- 应用场景
1、当语言的语法较为简单,且执行效率不是关键问题时。
2、当问题重复出现,且可以用一种简单的语言来进行表达时。
3、当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。
注意:解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。如果碰到对表达式的解释,在 Java 中可以用 Expression4J 或 Jep 等来设计。