解釋器模式
意圖
給定一個語言,定義他的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子
動機
目前計算機編程語言有好幾百種,但有時候我們還是希望能用一些簡單的語言來實現一些特定的操作,我們只要向計算機輸入一個句子或文件,它就能夠按照預先定義的文法規則來對句子或文件進行解釋,從而實現相應的功能。例如當輸入字符串表達式爲“1 + 2 + 3 ”時,將輸出計算結果爲6
適用性
1、可以將一個需要解釋執行的語言中的句子表示爲一個抽象語法樹
2、一些重複出現的問題可以用一種簡單的語言來進行表達。
3、一個語言的文法較爲簡單。
4、執行效率不是關鍵問題。
結構
AbstractExpression
聲明一個抽象的解釋操作,這個接口爲抽象語法樹中所有節點共享
TerminalExpression
實現與文法中的終結符相關聯的解釋操作
一個橘子中的每個終結符需要該類的一個實例
NonterminalExpression
對文法中每一條規則都需要一個這樣的類
Context
包含解釋器之外的一些全局信息
實現
實現一個輸入類似“4*8/9%2”類似的表達式,輸出對應的結果
package interpreter;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:45
* 抽象表達式
*/
public interface Node {
int interpret();
}
package interpreter;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:48
* 非終結表達式
*/
public class ValueNode implements Node {
private int value;
public ValueNode(int value) {
this.value = value;
}
@Override
public int interpret() {
return this.value;
}
}
package interpreter;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:49
* 終結表達式抽象類,由於該終結表達式需要解釋多個運算符號,同時用來構建抽象語法樹
*/
public abstract class SymbolNode implements Node {
protected Node left;
protected Node right;
public SymbolNode(Node left, Node right) {
this.left = left;
this.right = right;
}
}
package interpreter;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:51
*/
public class MulNode extends SymbolNode {
public MulNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() * right.interpret();
}
}
package interpreter;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:51
*/
public class ModNode extends SymbolNode {
public ModNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() % right.interpret();
}
}
package interpreter;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:51
*/
public class DivNode extends SymbolNode {
public DivNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() / right.interpret();
}
}
package interpreter;
import java.util.Stack;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:52
*/
public class Calculator {
private String statement;
private Node node;
public void build(String statement) {
Node left, right;
Stack stack = new Stack();
String[] statementArr = statement.split(" ");
for (int i = 0; i < statementArr.length; i++) {
if (statementArr[i].equalsIgnoreCase("*")) {
left = (Node) stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new MulNode(left, right));
} else if (statementArr[i].equalsIgnoreCase("/")) {
left = (Node) stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new DivNode(left, right));
} else if (statementArr[i].equalsIgnoreCase("%")) {
left = (Node) 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 = (Node) stack.pop();
}
public int compute() {
return node.interpret();
}
}
package interpreter;
/**
* @Author fitz.bai
* @Date 2018/9/4 18:45
*/
public class Client {
public static void main(String[] args) {
String statement = "3 * 5 / 2 % 2";
Calculator calculator = new Calculator();
calculator.build(statement);
int result = calculator.compute();
System.out.println(result);
}
}
####優點
1、 擴展性比較好,靈活
2、 增加新的解釋表達式方便。
3、 易於實現文法
缺點
1、 執行效率比較低,可利用場景比較少。
2、 對於複雜的文法比較難維護。