java設(shè)計(jì)模式 - 解釋器模式

1.定義

給分析對(duì)象定義一個(gè)語言,并定義該語言的文法表示,再設(shè)計(jì)一個(gè)解析器來解釋語言中的句子。也就是說,用編譯語言的方式來分析應(yīng)用中的實(shí)例。這種模式實(shí)現(xiàn)了文法表達(dá)式處理的接口,該接口解釋一個(gè)特定的上下文

這里提到的文法和句子的概念同編譯原理中的描述相同,“文法”指語言的語法規(guī)則,而“句子”是語言集中的元素。例如,漢語中的句子有很多,“我是中國(guó)人”是其中的一個(gè)句子,可以用一棵語法樹來直觀地描述語言中的句子


2.優(yōu)缺點(diǎn)

主要優(yōu)點(diǎn)如下:

  • 擴(kuò)展性好。由于在解釋器模式中使用類來表示語言的文法規(guī)則,因此可以通過繼承等機(jī)制來改變或擴(kuò)展文法。
  • 容易實(shí)現(xiàn)。在語法樹中的每個(gè)表達(dá)式節(jié)點(diǎn)類都是相似的,所以實(shí)現(xiàn)其文法較為容易。

主要缺點(diǎn)如下:

  • 執(zhí)行效率較低。解釋器模式中通常使用大量的循環(huán)和遞歸調(diào)用,當(dāng)要解釋的句子較復(fù)雜時(shí),其運(yùn)行速度很慢,且代碼的調(diào)試過程也比較麻煩。
  • 會(huì)引起類膨脹。解釋器模式中的每條規(guī)則至少需要定義一個(gè)類,當(dāng)包含的文法規(guī)則很多時(shí),類的個(gè)數(shù)將急劇增加,導(dǎo)致系統(tǒng)難以管理與維護(hù)。
  • 可應(yīng)用的場(chǎng)景比較少。在軟件開發(fā)中,需要定義語言文法的應(yīng)用實(shí)例非常少,所以這種模式很少被使用到

3.結(jié)構(gòu)

解釋器模式常用于對(duì)簡(jiǎn)單語言的編譯或分析實(shí)例中,為了掌握好它的結(jié)構(gòu)與實(shí)現(xiàn),必須先了解編譯原理中的“文法、句子、語法樹”等相關(guān)概念。
1) 文法
文法是用于描述語言的語法結(jié)構(gòu)的形式規(guī)則。沒有規(guī)矩不成方圓,例如,有些人認(rèn)為完美愛情的準(zhǔn)則是“相互吸引、感情專一、任何一方都沒有戀愛經(jīng)歷”,雖然最后一條準(zhǔn)則較苛刻,但任何事情都要有規(guī)則,語言也一樣,不管它是機(jī)器語言還是自然語言,都有它自己的文法規(guī)則。例如,中文中的“句子”的文法如下。

〈句子〉::=〈主語〉〈謂語〉〈賓語〉
〈主語〉::=〈代詞〉|〈名詞〉
〈謂語〉::=〈動(dòng)詞〉
〈賓語〉::=〈代詞〉|〈名詞〉
〈代詞〉你|我|他
〈名詞〉7大學(xué)生I筱霞I英語
〈動(dòng)詞〉::=是|學(xué)習(xí)

注:這里的符號(hào)“::=”表示“定義為”的意思,用“〈”和“〉”括住的是非終結(jié)符,沒有括住的是終結(jié)符。

2) 句子
句子是語言的基本單位,是語言集中的一個(gè)元素,它由終結(jié)符構(gòu)成,能由“文法”推導(dǎo)出。例如,上述文法可以推出“我是大學(xué)生”,所以它是句子。

3) 語法樹
語法樹是句子結(jié)構(gòu)的一種樹型表示,它代表了句子的推導(dǎo)結(jié)果,它有利于理解句子語法結(jié)構(gòu)的層次。圖 1 所示是“我是大學(xué)生”的語法樹。

句子“我是大學(xué)生”的語法樹.png

解釋器模式的結(jié)構(gòu)與組合模式相似,不過其包含的組成元素比組合模式多,而且組合模式是對(duì)象結(jié)構(gòu)型模式,而解釋器模式是類行為型模式

解釋器模式包含以下主要角色:

  • 抽象表達(dá)式(Abstract Expression角色:定義解釋器的接口,約定解釋器的解釋操作,主要包含解釋方法 interpret()。
  • 終結(jié)符表達(dá)式(Terminal Expression角色:是抽象表達(dá)式的子類,用來實(shí)現(xiàn)文法中與終結(jié)符相關(guān)的操作,文法中的每一個(gè)終結(jié)符都有一個(gè)具體終結(jié)表達(dá)式與之相對(duì)應(yīng)。
  • 非終結(jié)符表達(dá)式(Nonterminal Expression角色:也是抽象表達(dá)式的子類,用來實(shí)現(xiàn)文法中與非終結(jié)符相關(guān)的操作,文法中的每條規(guī)則都對(duì)應(yīng)于一個(gè)非終結(jié)符表達(dá)式。
  • 環(huán)境(Context角色:通常包含各個(gè)解釋器需要的數(shù)據(jù)或是公共的功能,一般用來傳遞被所有解釋器共享的數(shù)據(jù),后面的解釋器可以從這里獲取這些值。
  • 客戶端(Client:主要任務(wù)是將需要分析的句子或表達(dá)式轉(zhuǎn)換成使用解釋器對(duì)象描述的抽象語法樹,然后調(diào)用解釋器的解釋方法,當(dāng)然也可以通過環(huán)境角色間接訪問解釋器的解釋方法。
結(jié)構(gòu)圖.png

4.示例代碼

/*文法規(guī)則
  <expression> ::= <city>的<person>
  <city> ::= 韶關(guān)|廣州
  <person> ::= 老人|婦女|兒童
*/
public class InterpreterPatternDemo {
    public static void main(String[] args) {
        Context bus = new Context();
        bus.freeRide("韶關(guān)的老人");
        bus.freeRide("韶關(guān)的年輕人");
        bus.freeRide("廣州的婦女");
        bus.freeRide("廣州的兒童");
        bus.freeRide("山東的兒童");
    }
}
//抽象表達(dá)式類
interface Expression {
    public boolean interpret(String info);
}
//終結(jié)符表達(dá)式類
class TerminalExpression implements Expression {
    private Set<String> set = new HashSet<String>();
    public TerminalExpression(String[] data) {
        for (int i = 0; i < data.length; i++) set.add(data[i]);
    }
    public boolean interpret(String info) {
        if (set.contains(info)) {
            return true;
        }
        return false;
    }
}
//非終結(jié)符表達(dá)式類
class AndExpression implements Expression {
    private Expression city = null;
    private Expression person = null;
    public AndExpression(Expression city, Expression person) {
        this.city = city;
        this.person = person;
    }
    public boolean interpret(String info) {
        String s[] = info.split("的");
        return city.interpret(s[0]) && person.interpret(s[1]);
    }
}
//環(huán)境類
class Context {
    private String[] citys = {"韶關(guān)", "廣州"};
    private String[] persons = {"老人", "婦女", "兒童"};
    private Expression cityPerson;
    public Context() {
        Expression city = new TerminalExpression(citys);
        Expression person = new TerminalExpression(persons);
        cityPerson = new AndExpression(city, person);
    }
    public void freeRide(String info) {
        boolean ok = cityPerson.interpret(info);
        if (ok) System.out.println("您是" + info + ",您本次乘車免費(fèi)!");
        else System.out.println(info + ",您不是免費(fèi)人員,本次乘車扣費(fèi)2元!");
    }
}

執(zhí)行結(jié)果如下:

您是韶關(guān)的老人,您本次乘車免費(fèi)!
韶關(guān)的年輕人,您不是免費(fèi)人員,本次乘車扣費(fèi)2元!
您是廣州的婦女,您本次乘車免費(fèi)!
您是廣州的兒童,您本次乘車免費(fèi)!
山東的兒童,您不是免費(fèi)人員,本次乘車扣費(fèi)2元!

5.應(yīng)用場(chǎng)景

  1. 當(dāng)語言的文法較為簡(jiǎn)單,且執(zhí)行效率不是關(guān)鍵問題時(shí)。
  2. 當(dāng)問題重復(fù)出現(xiàn),且可以用一種簡(jiǎn)單的語言來進(jìn)行表達(dá)時(shí)。
  3. 當(dāng)一個(gè)語言需要解釋執(zhí)行,并且語言中的句子可以表示為一個(gè)抽象語法樹的時(shí)候,如 XML 文檔解釋。

注意:解釋器模式在實(shí)際的軟件開發(fā)中使用比較少,因?yàn)樗鼤?huì)引起效率、性能以及維護(hù)等問題。如果碰到對(duì)表達(dá)式的解釋,在 Java中可以用 Expression4JJep等來設(shè)計(jì)。


6.參考

解釋器模式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容