解釋器模式定義語言的文法,並且建立一個解釋器來解釋該語言中的句子。它屬於類的行為模式。這里的語言意思是使用規定格式和語法的代碼。
應用環境:
如果一種特定類型的問題發生的頻率足夠高,那么可能就值得將該問題的各個實例表述為一個簡單語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。而且當文法簡單、效率不是關鍵問題的時候效果最好。
類圖:
抽象表達式角色(AbstractExpression): 聲明一個抽象的解釋操作,這個接口為所有具體表達式角色都要實現的.
終結符表達式角色(TerminalExpression): 實現與文法中的元素相關聯的解釋操作,通常一個解釋器模式中只有一個終結符表達式,但有多個實例對應不同的終結符.
終結符就是語言中用到的基本元素,一般不能再被分解,如: x -> xa, 這里a是終結符,因為沒有別的規則可以把a變成別的符號,不過x可以變成別的符號,所以x是非終結符.
非終結符表達式角色(NonterminalExpression): 文法中的每條規則對應於一個非終結表達式, 非終結表達式根據邏輯的復雜程度而增加,原則上每個文法規則都對應一個非終結符表達式.
環境角色(Context): 包含解釋器之外的一些全局信息.
實例:計算(a*b)/(a-b+2)
public class Context
{
private final Map<String, Integer> valueMap = new HashMap<String, Integer>();
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等腳本語言來代替解釋器模式。