推荐:​​Java设计模式汇总​​

解释器模式

定义

Given a language,define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

类型
行为型。

角色

  • AbstractExpression(抽象表达式):在抽象表达式中声明抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。
  • TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。
  • NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
  • Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。

例子
这里举计算后缀表达式的例子,为了更加简化,这里只处理两种运算符​​​+​​​、​​*​​,没有括号,并且默认后缀表达式是正确的。

Interpreter接口(抽象表达式)。

package com.kaven.design.pattern.behavioral.interpreter;

public interface Interpreter {
int interpret();
}

NumberInterpreter类(非终结符表达式),实现了Interpreter接口。

package com.kaven.design.pattern.behavioral.interpreter;

public class NumberInterpreter implements Interpreter {
private int number;
public NumberInterpreter(int number){
this.number = number;
}
public NumberInterpreter(String number){
this.number = Integer.parseInt(number);
}
public int interpret() {
return this.number;
}
}

AddInterpreter类(终结符表达式),实现了Interpreter接口。

package com.kaven.design.pattern.behavioral.interpreter;

public class AddInterpreter implements Interpreter {

private Interpreter firstExpression,secondExpression;

public AddInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
this.firstExpression = firstExpression;
this.secondExpression = secondExpression;
}

public int interpret() {
return this.firstExpression.interpret()+this.secondExpression.interpret();
}

public String toString(){
return "+";
}
}

MultiInterpreter类(终结符表达式),实现了Interpreter接口。

package com.kaven.design.pattern.behavioral.interpreter;

public class MultiInterpreter implements Interpreter {
private Interpreter firstExpression,secondExpression;

public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
this.firstExpression = firstExpression;
this.secondExpression = secondExpression;
}

public int interpret() {
return this.firstExpression.interpret()*this.secondExpression.interpret();
}

public String toString(){
return "*";
}
}

OperatorUtil类(操作工具类)。

package com.kaven.design.pattern.behavioral.interpreter;

public class OperatorUtil {
public static boolean isOperator(String symbol){
return (symbol.equals("+") || symbol.equals("*"));
}

public static Interpreter getExpressionObject(Interpreter firstExpression ,
Interpreter secondExpression ,
String symbol){
if(symbol.equals("+")){
return new AddInterpreter(firstExpression , secondExpression);
}
else if(symbol.equals("*")){
return new MultiInterpreter(firstExpression , secondExpression);
}
return null;
}
}

KavenExpressionParser类,这里使用了上面实现的解释器模式相关类和​​Stack​​实现了计算后缀表达式的逻辑,计算后缀表达式的算法应该是数据结构的基础吧,这里就不讲了。

package com.kaven.design.pattern.behavioral.interpreter;

import java.util.Stack;

public class KavenExpressionParser {
private Stack<Interpreter> stack = new Stack<Interpreter>();

public int parse(String str){
String[] strItemArray = str.split(" ");
for(String symbol : strItemArray){
if(!OperatorUtil.isOperator(symbol)){
Interpreter numberExpression = new NumberInterpreter(symbol);
stack.push(numberExpression);
System.out.println(String.format("入栈:%d",numberExpression.interpret()));
}
else{
// 是运算符号可以计算
Interpreter firstExpression = stack.pop();
Interpreter secondExpression = stack.pop();
System.out.println(String.format("出栈:%d 和 %d",
firstExpression.interpret(),secondExpression.interpret()));
Interpreter operator = OperatorUtil.getExpressionObject(firstExpression ,
secondExpression , symbol);
System.out.println(String.format("应用运算符: %s",operator));
int result = operator.interpret();
NumberInterpreter resultExpression = new NumberInterpreter(result);
stack.push(resultExpression);
System.out.println(String.format("阶段结果入栈:%d",resultExpression.interpret()));
}
}
int result = stack.pop().interpret();
return result;
}
}

Expression类(环境类),存储后缀表达式。

package com.kaven.design.pattern.behavioral.interpreter;

public class Expression {
private String expression;

public Expression(String expression) {
this.expression = expression;
}

public String getExpression() {
return this.expression;
}
}

应用层代码:

package com.kaven.design.pattern.behavioral.interpreter;

public class Test {
public static void main(String[] args) {
Expression expression = new Expression("6 100 11 + *");
KavenExpressionParser expressionParser = new KavenExpressionParser();
int result = expressionParser.parse(expression.getExpression());
System.out.println("解释器计算结果"+result);
}
}

输出:

入栈:6
入栈:100
入栈:11
出栈:11 和 100
应用运算符: +
阶段结果入栈:111
出栈:111 和 6
应用运算符: *
阶段结果入栈:666
解释器计算结果666

这里便完成了一个简单的解释器模式例子。

适用场景

  • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  • 一些重复出现的问题可以用一种简单的语言进行表达。
  • 执行效率不是关键问题。高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。

优点

  • 易于改变和扩展文法。由于在解释器模式中使用类表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
  • 实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。

缺点

  • 解释器模式会引起类膨胀。
  • 解释器模式将会导致系统比较复杂, 为维护带来了非常多的麻烦。
  • 执行效率低。由于在解释器模式中一般采用了大量的循环和递归调用(我们的例子是使用栈来代替递归),因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

如果有说错的地方,请大家不吝赐教(记得留言哦~~~~)。