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

1.定義

給分析對象定義一個語言和二,并定義該語言的文法表示缔赠,再設(shè)計一個解析器來解釋語言中的句子缩功。也就是說夕膀,用編譯語言的方式來分析應(yīng)用中的實例果善。這種模式實現(xiàn)了文法表達式處理的接口诊笤,該接口解釋一個特定的上下文

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


2.優(yōu)缺點

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

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

主要缺點如下:

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

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

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

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

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

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

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

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

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

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

  • 抽象表達式(Abstract Expression角色:定義解釋器的接口乖寒,約定解釋器的解釋操作猴蹂,主要包含解釋方法 interpret()。
  • 終結(jié)符表達式(Terminal Expression角色:是抽象表達式的子類楣嘁,用來實現(xiàn)文法中與終結(jié)符相關(guān)的操作磅轻,文法中的每一個終結(jié)符都有一個具體終結(jié)表達式與之相對應(yīng)。
  • 非終結(jié)符表達式(Nonterminal Expression角色:也是抽象表達式的子類逐虚,用來實現(xiàn)文法中與非終結(jié)符相關(guān)的操作聋溜,文法中的每條規(guī)則都對應(yīng)于一個非終結(jié)符表達式。
  • 環(huán)境(Context角色:通常包含各個解釋器需要的數(shù)據(jù)或是公共的功能叭爱,一般用來傳遞被所有解釋器共享的數(shù)據(jù)撮躁,后面的解釋器可以從這里獲取這些值。
  • 客戶端(Client:主要任務(wù)是將需要分析的句子或表達式轉(zhuǎn)換成使用解釋器對象描述的抽象語法樹买雾,然后調(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("山東的兒童");
    }
}
//抽象表達式類
interface Expression {
    public boolean interpret(String info);
}
//終結(jié)符表達式類
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é)符表達式類
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 + "漓穿,您本次乘車免費嗤军!");
        else System.out.println(info + ",您不是免費人員晃危,本次乘車扣費2元叙赚!");
    }
}

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

您是韶關(guān)的老人,您本次乘車免費山害!
韶關(guān)的年輕人纠俭,您不是免費人員,本次乘車扣費2元浪慌!
您是廣州的婦女,您本次乘車免費朴则!
您是廣州的兒童权纤,您本次乘車免費钓简!
山東的兒童,您不是免費人員汹想,本次乘車扣費2元外邓!

5.應(yīng)用場景

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

注意:解釋器模式在實際的軟件開發(fā)中使用比較少庞萍,因為它會引起效率拧烦、性能以及維護等問題。如果碰到對表達式的解釋钝计,在 Java中可以用 Expression4JJep等來設(shè)計恋博。


6.參考

解釋器模式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市私恬,隨后出現(xiàn)的幾起案子债沮,更是在濱河造成了極大的恐慌,老刑警劉巖本鸣,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秦士,死亡現(xiàn)場離奇詭異,居然都是意外死亡永高,警方通過查閱死者的電腦和手機隧土,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來命爬,“玉大人曹傀,你說我怎么就攤上這事∷峭穑” “怎么了皆愉?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長艇抠。 經(jīng)常有香客問我幕庐,道長,這世上最難降的妖魔是什么家淤? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任异剥,我火速辦了婚禮,結(jié)果婚禮上絮重,老公的妹妹穿的比我還像新娘冤寿。我一直安慰自己歹苦,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布督怜。 她就那樣靜靜地躺著殴瘦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪号杠。 梳的紋絲不亂的頭發(fā)上蚪腋,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音姨蟋,去河邊找鬼屉凯。 笑死,一個胖子當(dāng)著我的面吹牛芬探,可吹牛的內(nèi)容都是我干的神得。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼偷仿,長吁一口氣:“原來是場噩夢啊……” “哼哩簿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酝静,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤节榜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后别智,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宗苍,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年薄榛,在試婚紗的時候發(fā)現(xiàn)自己被綠了讳窟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡敞恋,死狀恐怖丽啡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硬猫,我是刑警寧澤补箍,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站啸蜜,受9級特大地震影響坑雅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衬横,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一裹粤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冕香,春花似錦蛹尝、人聲如沸后豫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至构眯,卻和暖如春愕难,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惫霸。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工猫缭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壹店。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓猜丹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親硅卢。 傳聞我的和親對象是個殘疾皇子射窒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容