解釋器模式定義語言的文法,并且建立一個解釋器來解釋該語言中的句子。它屬于類的行為模式。這裡的語言意思是使用規定格式和文法的代碼。
應用環境:
如果一種特定類型的問題發生的頻率足夠高,那麼可能就值得将該問題的各個執行個體表述為一個簡單語言中的句子。這樣就可以建構一個解釋器,該解釋器通過解釋這些句子來解決該問題。而且當文法簡單、效率不是關鍵問題的時候效果最好。
類圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYWan5SY1kTMkJ2YwcjNyUjYxUjZzkDZiFDZhdTO4YzNwUWM18CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
抽象表達式角色(AbstractExpression): 聲明一個抽象的解釋操作,這個接口為所有具體表達式角色都要實作的.
終結符表達式角色(TerminalExpression): 實作與文法中的元素相關聯的解釋操作,通常一個解釋器模式中隻有一個終結符表達式,但有多個執行個體對應不同的終結符.
終結符就是語言中用到的基本元素,一般不能再被分解,如: x -> xa, 這裡a是終結符,因為沒有别的規則可以把a變成别的符号,不過x可以變成别的符号,是以x是非終結符.
非終結符表達式角色(NonterminalExpression): 文法中的每條規則對應于一個非終結表達式, 非終結表達式根據邏輯的複雜程度而增加,原則上每個文法規則都對應一個非終結符表達式.
環境角色(Context): 包含解釋器之外的一些全局資訊.
執行個體:計算(a*b)/(a-b+2)
public class Context
{
private final Map valueMap = new HashMap();
public void addValue(final String key, final int value)
{
valueMap.put(key, Integer.valueOf(value));
}
public int getValue(final String key)
{
return valueMap.get(key).intValue();
}
}
public abstract class AbstractExpression
{
public abstract int interpreter(Context context);
}
public class AddNonterminalExpression extends AbstractExpression
{
private final AbstractExpression left;
private final AbstractExpression right;
public AddNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
{
this.left = left;
this.right = right;
}
@Override
public int interpreter(final Context context)
{
return this.left.interpreter(context) + this.right.interpreter(context);
}
}
public class DivisionNonterminalExpression extends AbstractExpression
{
private final AbstractExpression left;
private final AbstractExpression right;
public DivisionNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
{
this.left = left;
this.right = right;
}
@Override
public int interpreter(final Context context)
{
final int value = this.right.interpreter(context);
if (value != 0)
{
return this.left.interpreter(context) / value;
}
return -1111;
}
}
public class MultiplyNonterminalExpression extends AbstractExpression
{
private final AbstractExpression left;
private final AbstractExpression right;
public MultiplyNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
{
this.left = left;
this.right = right;
}
@Override
public int interpreter(final Context context)
{
return this.left.interpreter(context) * this.right.interpreter(context);
}
}
public class SubtractNonterminalExpression extends AbstractExpression
{
private final AbstractExpression left;
private final AbstractExpression right;
public SubtractNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
{
this.left = left;
this.right = right;
}
@Override
public int interpreter(final Context context)
{
return this.left.interpreter(context) - this.right.interpreter(context);
}
}
public class TerminalExpression extends AbstractExpression
{
private final int i;
public TerminalExpression(final int i)
{
this.i = i;
}
@Override
public int interpreter(final Context context)
{
return this.i;
}
}
public class Client
{
//(a*b)/(a-b+2)
public static void main(final String[] args)
{
final Context context = new Context();
context.addValue("a", 7);
context.addValue("b", 8);
context.addValue("c", 2);
final MultiplyNonterminalExpression multiplyValue = new MultiplyNonterminalExpression(new TerminalExpression(
context.getValue("a")), new TerminalExpression(context.getValue("b")));
final SubtractNonterminalExpression subtractValue = new SubtractNonterminalExpression(new TerminalExpression(
context.getValue("a")), new TerminalExpression(context.getValue("b")));
final AddNonterminalExpression addValue = new AddNonterminalExpression(subtractValue, new TerminalExpression(
context.getValue("c")));
final DivisionNonterminalExpression divisionValue = new DivisionNonterminalExpression(multiplyValue, addValue);
System.out.println(divisionValue.interpreter(context));
}
}
結果:
56
優點:
解釋器是一個簡單文法分析工具,它最顯著的優點就是擴充性,修改文法規則隻要修改相應的非終結符表達式就可以了,若擴充文法,則隻要增加非終結符類就可以了。
缺點:
解釋器模式會引起類膨脹,每個文法都要産生一個非終結符表達式,文法規則比較複雜時,可能産生大量的類檔案,難以維護。
解釋器模式采用遞歸調用方法,它導緻調試非常複雜。
解釋器由于使用了大量的循環和遞歸,是以當用于解析複雜、冗長的文法時,效率是難以忍受的
注意事項:
盡量不要在重要子產品中使用解釋器模式,因為維護困難。在項目中,可以使用shell,JRuby,Groovy等腳本語言來代替解釋器模式。