一、解釋器模式的介紹:
解釋器是一種用的比較少的行為模式,其提供了一種解釋語言的語法,或者表達式的方式。該模式定義了一個表達式的接口。
有兩個重點需要關注的地方:
1、必須有一個抽象接口
2、構建語法樹
二、應用場景
2.1簡單的語言需要解釋執行而且可以將該語言中的語句表示一個抽象的語法樹
2.2對于某個特定的領域出現的不斷重復的問題,可以轉換成一種語法規則下的語句
三、解釋器模式結構圖
四、角色分析
** 抽象表達式角色:**聲明一個抽象的解釋操作,這個接口為所有具體表達式角色(抽象語法樹中的節點)都要實現的。
終結符表達式角色:具體表達式。實現與文法中的終結符相關聯的解釋操作,而且句子中的每個終結符需要該類的一個實例與之對應。
非終結符表達式角色:具體表達式。文法中的每條規則R::=R1R2…Rn都需要一個非終結符表帶式角色,對于從R1到Rn的每個符號都維護一個抽象表達式角色的實例變量,實現解釋操作,解釋一般要遞歸地調用表示從R1到Rn的那些對象的解釋操作。
上下文(環境)角色:包含解釋器之外的一些全局信息。
客戶角色:構建(或者被給定)表示該文法定義的語言中的一個特定的句子的抽象語法樹,調用解釋操作。
五、例子代碼實現
這里以實現3 X5 X 7 / 3的結果為例子說明
抽象表達式,定義一個方法用于表示乘或者除的表達式,由子類實現
public interface Node {
public int interpret();
}
終結符表達式角色
public class ValueNode implements Node{
private int value; //終結符 不能被分解
public ValueNode(int value) {
this.value = value;
}
public int interpret() {
return value;
}
}
非終結符表達式角色(具體的乘法或者除法交給子類去實現)
public abstract class SymbolNode implements Node{
//非終結符
protected Node left;
protected Node right;
public SymbolNode(Node left,Node right) {
this.left = left;
this.right = right;
}
}
計算乘法
/**
* 運算成分
* @author dell
*
*/
public class MulNode extends SymbolNode{
public MulNode(Node left, Node right) {
super(left, right);
}
/**
* 計算懲罰
*/
public int interpret() {
System.out.println("調用乘法");
return left.interpret()*right.interpret();
}
}
計算除法
package com.wzc.Interoreter;
public class DivNode extends SymbolNode{
public DivNode(Node left, Node right) {
super(left, right);
}
/**
* 計算除法
*/
public int interpret() {
return left.interpret()/right.interpret();
}
}
client角色,構建抽象語法樹
public class Calculate {
public int build(String statement){
Node left = null;
Node right = null;
Node lastNode = null;
String[] statements = statement.split(" ");
for(int i=0;i<statements.length;i++){
if("*".equals(statements[i])){
//計算乘法
left = lastNode;
int val = Integer.parseInt(statements[++i]);
right = new ValueNode(val);
//此時 新建了一個非終結符
lastNode = new MulNode(left,right);
}else if("/".equals(statements[i])){
//計算除法
left = lastNode;
int val = Integer.parseInt(statements[++i]);
right = new ValueNode(val);
//此時 新建了一個非終結符
lastNode = new DivNode(left,right);
}else{
//是數字 就添加進來 終結符
lastNode = new ValueNode(Integer.parseInt(statements[i]));
}
}
return lastNode.interpret();
}
}
在main函數中打印結果
public static void main(String[] args) {
String contentString = "3 * 5 * 7 / 3";
Calculate calculate = new Calculate();
int result = calculate.build(contentString);
System.out.println("---->"+result);
}
六、總結
1、 每個語法都要產生一個非終結符表達式,語法規則比較復雜時,就可能產生大量的類文件,為維護帶來了非常多的麻煩。
2、解釋器模式采用遞歸調用方法每個非終結符表達式只關心與自己有關的表達式,每個表達式需要知道最終的結果,必須一層一層地剝繭,無論是面向過程的語言還是面向對象的語言,遞歸都是在必要條件下使用的,它導致調試非常復雜。想想看,如果要排查一個語法錯誤,我們是不是要一個一個斷點的調試下去,直到最小的語法單元。
3、解釋器模式由于使用了大量的循環和遞歸,效率是個不容忽視的問題,特別是用于解析復雜、冗長的語法時,效率是難以忍受的。