一、简介
1.1 模式定义
定义语言的文法,并且建立一个解析器来解释该语言中的句子,这里的“语言”意思是使用规定格式和语法的代码,它是一种类行为型,模式。
1.2 适用场景
1)可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
2)一些重复出现的问题可以用一种简单的语言来进行表达。
3)文法较为简单。对于复杂的文法,解释器模式中的文法类层次结构将变得很庞大而无法管理,此时最好使用语法分析程序生成器。
4)效率不是关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是需要将它们转换成另外一种形式,使用解释器模式的执行效率并不高。
1.3 优点
1)易于改变和扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承机制来改变或扩展文法,实现简单语言方便。
2)易于实现文法。在抽象语法树中每个节点类的实现方式都是相似的,这些类的编写都不是很复杂,它们还可以通过一些工具自动生成。
3)增加了新的解释表达式的方法。解释器模式可以让用户较为方便地增加新类型的表达式,增加新的表达式时无须对现有表达式类进行修改,符合“开闭原则”。
1.4 缺点
1)对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,则可能难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。
2)执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时期速度很慢。
3)应用场景很有限,在软件开发中很少需要自定义文法规则,因此该语言的使用频率很低,在一般的软件中难以找到其应用实例,导致理解和使用该模式的难度增大。
二、示例
2.1 结构图
2.2 抽象表达式类Node(抽象节点)
public interface Node {
public int interpret();
}
2.3 终结符表达式类ValueNode(值节点类)
public class ValueNode implements Node{
private int value;
public ValueNode(int value) {
this.value = value;
}
@Override
public int interpret() {
return value;
}
}
2.4 抽象非终结符表达式类SymbolNode(符号节点类)
public abstract class SymbolNode implements Node{
protected Node left;
protected Node right;
public SymbolNode(Node left, Node right) {
this.left = left;
this.right = right;
}
}
2.5 非终结符表达式类DivNode(除法节点类)
public class DivNode extends SymbolNode{
public DivNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return super.left.interpret() / super.right.interpret();
}
}
2.6 非终结符表达式类ModeNode(求模节点类)
public class ModNode extends SymbolNode{
public ModNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() % right.interpret();
}
}
2.7 非终结符表达式类MulNode(乘法节点类)
public class MulNode extends SymbolNode{
public MulNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return super.left.interpret() * super.right.interpret();
}
}
2.8 解释器封装类Calculator(计算器类)
public class Calculator {
private Node node;
public void build(String statement) {
Node left = null,right = null;
Stack<Node> stack = new Stack<>();
String[] statementArr = statement.split(" ");
for (int i = 0; i < statementArr.length; i++) {
if (statementArr[i].equalsIgnoreCase("*")) {
left = stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new MulNode(left, right));
}else if (statementArr[i].equalsIgnoreCase("/")) {
left = stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new DivNode(left, right));
} else if (statementArr[i].equalsIgnoreCase("%")) {
left = stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new ModNode(left, right));
} else {
stack.push(new ValueNode(Integer.parseInt(statementArr[i])));
}
}
this.node = stack.pop();
}
public int compute() {
return node.interpret();
}
}
2.9 客户端类Demo类
public class Demo {
public static void main(String[] args) {
String statement = "3 * 4 / 2 % 4";
Calculator calculator = new Calculator();
calculator.build(statement);
int result = calculator.compute();
System.out.println(statement + " = " + result);
}
}