解釋器模式是一種使用頻率相對較低但學習難度較大的設計模式,它用於描述如何使用面向對象語言構成一個簡單的語言解釋器。 ...
簡介
在某些情況下,為了更好地描述某一些特定類型的問題,我們可以創建一種新的語言,這種語言擁有自己的表達式和結構,即文法規則。
解釋器設計模式(Interpreter Design Pattern)描述瞭如何為簡單的語言定義一個文法,如何在該語言中表示一個句子,以及如何解釋這些句子。
因此,解釋器模式的定義是,為某個語言定義它的語法(文法)表示,並定義一個解釋器用來處理這個語法。
典型實現
首先,需要定義一個抽象表達式類,其聲明瞭抽象的解釋操作,其代碼示例如下:
public abstract class AbstractExpression {
public abstract void interpret(Context context);
}
終結符表達式是抽象表達式的子類,它實現了與文法中的終結符相關聯的解釋操作,在句子中的每一個終結符都是該類的一個實例。其代碼示例如下:
public class TerminalExpression extends AbstractExpression {
public void interpret(Context context) {
// 終結符表達式的解釋操作
}
}
非終結符表達式類相對比較複雜,由於在非終結符表達式中可以包含終結符表達式,也可以繼續包含非終結符表達式,因此其解釋操作一般通過遞歸的方式來完成。其代碼示例如下:
public class NonTerminalExpression extends AbstractExpression {
private AbstractExpression left;
private AbstractExpression right;
public NonTerminalExpression(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
public void interpret(Context context) {
// 遞歸調用每一個組成部分的 interpret() 方法
// 在遞歸調用時指定組成部分的連接方式,即非終結符的功能
}
}
通常在解釋器模式中會提供一個環境類用於存儲一些全局信息,如使用 HashMap
或者 ArrayList
等類型的集合對象,存儲一系列公共信息,其代碼示例如下:
public class Context {
private HashMap<String, String> map = new HashMap<>();
public void assign(String key, String value) {
// 往環境中設值
map.put(key, value);
}
public String lookup(String key) {
// 獲取存儲在環境類中的值
return map.get(key);
}
}
總結
優點
解釋器模式的主要優點如下:
- 易於改變和擴展文法
- 每一條文法規則都可以表示為一個類,因此可以方便地實現一個簡單的語言
- 實現文法較為容易
- 增加新的解釋器表達式較為方便
缺點
解釋器模式的主要缺點如下:
- 對於複雜文法難以維護,增加文法規則會導致類急劇增加,導致系統難以管理和維護
- 解釋器模式使用了大量迴圈和遞歸調用,執行效率較低
適用場景
解釋器模式的適用場景如下:
- 可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹
- 一些重覆出現的問題可以用一種簡單的語言來進行表達
- 一個語言的文法較為簡單
源碼
在 JDK 中,java.text.Format
就是一個抽象表達式類的實現,如下是其部分源碼:
public abstract class Format implements Serializable, Cloneable {
AttributedCharacterIterator createAttributedCharacterIterator(String s) {
AttributedString as = new AttributedString(s);
return as.getIterator();
}
AttributedCharacterIterator createAttributedCharacterIterator(
AttributedCharacterIterator[] iterators) {
AttributedString as = new AttributedString(iterators);
return as.getIterator();
}
}