Go和Java實現解釋器模式
下面通過一個四則運算來說明解釋器模式的使用。
1、解釋器模式
解釋器模式提供了評估語言的語法或表達式的方式,它屬于行為型模式。這種模式實現了一個表達式接口,該接口
解釋一個特定的上下文。這種模式被用在 SQL 解析、符號處理引擎等。
-
意圖:給定一個語言,定義它的文法表示,并定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。
-
主要解決:對于一些固定文法構建一個解釋句子的解釋器。
-
何時使用:如果一種特定類型的問題發生的頻率足夠高,那么可能就值得將該問題的各個實例表述為一個簡單
語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。
-
如何解決:構建語法樹,定義終結符與非終結符。
-
關鍵代碼:構建環境類,包含解釋器之外的一些全局信息,一般是 HashMap。
-
應用實例:編譯器、運算表達式計算。
-
優點:1、可擴展性比較好,靈活。 2、增加了新的解釋表達式的方式。 3、易于實現簡單文法。
-
缺點:1、可利用場景比較少。 2、對于復雜的文法比較難維護。 3、解釋器模式會引起類膨脹。 4、解釋器模
式采用遞歸調用方法。
-
使用場景:1、可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹。 2、一些重復出現的問題可
以用一種簡單的語言來進行表達。 3、一個簡單語法需要解釋的場景。
-
注意事項:可利用場景比較少,JAVA 中如果碰到可以用 expression4J 代替。
-
適用性:
當有一個語言需要解釋執行,并且你可將該語言中的句子表示為一個抽象語法樹時,可使用解釋器模式,而當
存在當下情況時該模式效果最好:
該文法簡單對于復雜的文法,文法的層次變得龐大而無法管理。
效率不是一個關鍵問題最高效的解釋器通常不是通過直接解釋語法分析樹實現的,而是首先將它們轉換成另
一種形式。
2、Go實現解釋器模式
package interpreter// ========== ArithmeticInterpreter ==========
type ArithmeticInterpreter interface {Interpret() int
}
package interpreter// ========== NumInterpreter ==========
type NumInterpreter struct {Value int
}func NewNumInterpreter(value int) *NumInterpreter {return &NumInterpreter{Value: value}
}func (numInterpreter *NumInterpreter) Interpret() int {return numInterpreter.Value
}
package interpreter// ========== AddInterpreter ==========
type AddInterpreter struct {left ArithmeticInterpreterright ArithmeticInterpreter
}func NewAddInterpreter(left, right ArithmeticInterpreter) *AddInterpreter {return &AddInterpreter{left: left, right: right}
}func (addInterpreter *AddInterpreter) Interpret() int {return addInterpreter.left.Interpret() + addInterpreter.right.Interpret()
}
package interpreter// ========== SubInterpreter ==========
type SubInterpreter struct {left ArithmeticInterpreterright ArithmeticInterpreter
}func NewSubInterpreter(left, right ArithmeticInterpreter) *SubInterpreter {return &SubInterpreter{left: left, right: right}
}func (subInterpreter *SubInterpreter) Interpret() int {return subInterpreter.left.Interpret() - subInterpreter.right.Interpret()
}
package interpreter// ========== MultiInterpreter ==========
type MultiInterpreter struct {left ArithmeticInterpreterright ArithmeticInterpreter
}func NewMultiInterpreter(left, right ArithmeticInterpreter) *MultiInterpreter {return &MultiInterpreter{left: left, right: right}
}func (multiInterpreter *MultiInterpreter) Interpret() int {return multiInterpreter.left.Interpret() * multiInterpreter.right.Interpret()
}
package interpreter// ========== DivInterpreter ==========
type DivInterpreter struct {left ArithmeticInterpreterright ArithmeticInterpreter
}func NewDivInterpreter(left, right ArithmeticInterpreter) *DivInterpreter {return &DivInterpreter{left: left, right: right}
}func (divInterpreter *DivInterpreter) Interpret() int {return divInterpreter.left.Interpret() / divInterpreter.right.Interpret()
}
package interpreterconst (ADD = "+"SUB = "-"MUL = "*"DIV = "/"
)// =========== OperatorUtil ==========
type OperatorUtil struct{}func (OperatorUtil *OperatorUtil) IsOperator(symbol string) bool {return ("+" == symbol || "-" == symbol || "*" == symbol)
}func (operatorUtil *OperatorUtil) GetInterpreter(left, right ArithmeticInterpreter, symbol string) ArithmeticInterpreter {if ADD == symbol {return NewAddInterpreter(left, right)} else if SUB == symbol {return NewSubInterpreter(left, right)} else if MUL == symbol {return NewMultiInterpreter(left, right)} else if DIV == symbol {return NewDivInterpreter(left, right)}return nil
}
package interpreterimport ("fmt""strconv""strings"
)type Calculator struct{}var (operatorUtil = OperatorUtil{}stack = make([]ArithmeticInterpreter, 0)
)func (calculator *Calculator) Parse(expression string) {elements := strings.Split(expression, " ")var leftExpr, rightExpr ArithmeticInterpreterfor i := 0; i < len(elements); i++ {operator := elements[i]if operatorUtil.IsOperator(operator) {// 出棧leftExpr = stack[len(stack)-1]stack = stack[:len(stack)-1]i++ele, _ := strconv.Atoi(elements[i])rightExpr = NewNumInterpreter(ele)fmt.Printf("出棧: %d 和 %d \n", leftExpr.Interpret(), rightExpr.Interpret())stack = append(stack, operatorUtil.GetInterpreter(leftExpr, rightExpr, operator))fmt.Println("應用運算符: " + operator)} else {ele, _ := strconv.Atoi(elements[i])numInterpreter := NewNumInterpreter(ele)stack = append(stack, numInterpreter)fmt.Printf("入棧: %d \n", numInterpreter.Interpret())}}}func (calculator *Calculator) Result() int {value := stack[len(stack)-1]stack = stack[:len(stack)-1]return value.Interpret()
}
package mainimport ("fmt". "proj/interpreter"
)func main() {calculator := Calculator{}calculator.Parse("10 + 30")fmt.Println("result:", calculator.Result())calculator.Parse("10 + 30 - 20")fmt.Println("result: ", calculator.Result())calculator.Parse("100 * 2 + 400 - 20 + 66")fmt.Println("result:", calculator.Result())
}
# 程序輸出
入棧: 10
出棧: 10 和 30
應用運算符: +
result: 40
入棧: 10
出棧: 10 和 30
應用運算符: +
出棧: 40 和 20
應用運算符: -
result: 20
入棧: 100
出棧: 100 和 2
應用運算符: *
出棧: 200 和 400
應用運算符: +
出棧: 600 和 20
應用運算符: -
出棧: 580 和 66
應用運算符: +
result: 40
入棧: 10
出棧: 10 和 30
應用運算符: +
出棧: 40 和 20
應用運算符: -
result: 20
入棧: 100
出棧: 100 和 2
應用運算符: *
出棧: 200 和 400
應用運算符: +
出棧: 600 和 20
應用運算符: -
出棧: 580 和 66
應用運算符: +
result: 646
3、Java實現解釋器模式
package com.interpreter;// ========== ArithmeticInterpreter ==========
public interface ArithmeticInterpreter {int interpret();
}
package com.interpreter;// ========== ArithmeticInterpreter ==========
public abstract class Interpreter implements ArithmeticInterpreter{protected ArithmeticInterpreter left;protected ArithmeticInterpreter right;public Interpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {this.left = left;this.right = right;}
}
package com.interpreter;// ========== NumInterpreter ==========
public class NumInterpreter implements ArithmeticInterpreter {private int value;public NumInterpreter(int value) {this.value = value;}@Overridepublic int interpret() {return this.value;}}
package com.interpreter;// ========== AddInterpreter ==========
public class AddInterpreter extends Interpreter {public AddInterpreter() {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() + this.right.interpret();}
}
package com.interpreter;// ========== MultiInterpreter ==========
public class MultiInterpreter extends Interpreter {public MultiInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() * this.right.interpret();}
}
package com.interpreter;// ========== SubInterpreter ==========
public class SubInterpreter extends Interpreter {public SubInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() - this.right.interpret();}
}
package com.interpreter;// ========== DivInterpreter ==========
public class DivInterpreter extends Interpreter {public DivInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() / this.right.interpret();}
}
package com.interpreter;// =========== OperatorUtil ==========
public class OperatorUtil {private final static String ADD = "+";private final static String SUB = "-";private final static String MUL = "*";private final static String DIV = "/";public static boolean isOperator(String symbol) {return ("+".equals(symbol) || "-".equals(symbol) || "*".equals(symbol));}public static Interpreter getInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right, String symbol) {if (ADD.equals(symbol)) {return new AddInterpreter(left, right);} else if (SUB.equals(symbol)) {return new SubInterpreter(left, right);} else if (MUL.equals(symbol)) {return new MultiInterpreter(left, right);} else if (DIV.equals(symbol)) {return new DivInterpreter(left, right);}return null;}
}
package com.interpreter;import java.util.Stack;// ========== Calculator ==========
public class Calculator {private final Stack<ArithmeticInterpreter> stack = new Stack<>();public void parse(String expression) {String[] elements = expression.split(" ");ArithmeticInterpreter leftExpr, rightExpr;for (int i = 0; i < elements.length; i++) {String operator = elements[i];if (OperatorUtil.isOperator(operator)) {leftExpr = this.stack.pop();rightExpr = new NumInterpreter(Integer.parseInt(elements[++i]));System.out.println("出棧: " + leftExpr.interpret() + " 和 " + rightExpr.interpret());this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr, operator));System.out.println("應用運算符: " + operator);} else {NumInterpreter numInterpreter = new NumInterpreter(Integer.parseInt(elements[i]));this.stack.push(numInterpreter);System.out.println("入棧: " + numInterpreter.interpret());}}}public int result() {return this.stack.pop().interpret();}}
package com.interpreter;public class Test {public static void main(String[] args) {Calculator calculator = new Calculator();calculator.parse("10 + 30");System.out.println("result: " + calculator.result());calculator.parse("10 + 30 - 20");System.out.println("result: " + calculator.result());calculator.parse("100 * 2 + 400 - 20 + 66");System.out.println("result: " + calculator.result());}
}
# 程序輸出
入棧: 10
出棧: 10 和 30
應用運算符: +
result: 40
入棧: 10
出棧: 10 和 30
應用運算符: +
出棧: 40 和 20
應用運算符: -
result: 20
入棧: 100
出棧: 100 和 2
應用運算符: *
出棧: 200 和 400
應用運算符: +
出棧: 600 和 20
應用運算符: -
出棧: 580 和 66
應用運算符: +
result: 646