推薦: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
這裡便完成了一個簡單的解釋器模式例子。
适用場景
- 可以将一個需要解釋執行的語言中的句子表示為一個抽象文法樹。
- 一些重複出現的問題可以用一種簡單的語言進行表達。
- 執行效率不是關鍵問題。高效的解釋器通常不是通過直接解釋抽象文法樹來實作的,而是需要将它們轉換成其他形式,使用解釋器模式的執行效率并不高。
優點
- 易于改變和擴充文法。由于在解釋器模式中使用類表示語言的文法規則,是以可以通過繼承等機制來改變或擴充文法。
- 實作文法較為容易。在抽象文法樹中每一個表達式節點類的實作方式都是相似的,這些類的代碼編寫都不會特别複雜,還可以通過一些工具自動生成節點類代碼。
- 解釋器模式會引起類膨脹。
- 解釋器模式将會導緻系統比較複雜, 為維護帶來了非常多的麻煩。
- 執行效率低。由于在解釋器模式中一般采用了大量的循環和遞歸調用(我們的例子是使用棧來代替遞歸),是以在解釋較為複雜的句子時其速度很慢,而且代碼的調試過程也比較麻煩。