Android 解釋器模式

源碼地址

介紹

解釋器模式是一種使用的比較少的一種模式纷纫,其提供了一種解釋語(yǔ)言的語(yǔ)法或表達(dá)式的方式涕蚤,該模式定義了一個(gè)表達(dá)式接口卵酪,通過(guò)該接口解釋一個(gè)特定的上下文。(比較抽象熙掺,想了解建議查看原版書(shū)籍)

使用場(chǎng)景

  1. 如果某個(gè)簡(jiǎn)單的語(yǔ)言需要解釋執(zhí)行未斑,而且可以將該語(yǔ)言中的語(yǔ)句表示為一個(gè)抽象語(yǔ)法樹(shù)時(shí),可以考慮使用該模式币绩。比如有一個(gè)簡(jiǎn)單的數(shù)學(xué)表達(dá)式:p+q+m-n颂碧。
  2. 在某些特定領(lǐng)域出現(xiàn)不斷重復(fù)的問(wèn)題時(shí),可以將該領(lǐng)域的問(wèn)題轉(zhuǎn)換為一種語(yǔ)法規(guī)則下的語(yǔ)句类浪,然后構(gòu)建解釋器來(lái)解釋該語(yǔ)句载城。比如需要將一段阿拉伯?dāng)?shù)字轉(zhuǎn)換為中文的數(shù)字,又或者將某個(gè)小寫(xiě)英文短語(yǔ)轉(zhuǎn)換為大寫(xiě)费就。

UML 類(lèi)圖

解釋器模式UML.jpg

角色介紹诉瓦。

AbstractExpression: 抽象表達(dá)式。
聲明一個(gè)抽象的解釋操作父類(lèi)力细,并定義一個(gè)抽象的解釋方法睬澡,其具體的實(shí)現(xiàn)在各個(gè)具體的子類(lèi)解釋器中完成。

TerminalExpression: 終結(jié)符表達(dá)式眠蚂。
實(shí)現(xiàn)文法與終結(jié)符有關(guān)的解釋操作煞聪。文法中每一個(gè)終結(jié)符都有一個(gè)具體的終結(jié)表達(dá)式與之對(duì)應(yīng)。

NonternimalExpression: 非終結(jié)符表達(dá)式逝慧。
實(shí)現(xiàn)文法中與非終結(jié)符有關(guān)的解釋操作昔脯。

Context: 上下文環(huán)境類(lèi)。
包含解釋器之外的全局信息笛臣。

Client: 客戶(hù)類(lèi)云稚。
解析表達(dá)式,構(gòu)建抽象語(yǔ)法樹(shù)沈堡,執(zhí)行具體的解釋操作等静陈。

對(duì)應(yīng)通用模式代碼

// 抽象表達(dá)式
public abstract class AbstractExpression {
    /**
     * 抽象的解析方法
     */
    public abstract void interpret(Context ctx);
}

// 終結(jié)符表達(dá)式
public class TerminalExpression extends AbstractExpression {
    @Override
    public void interpret(Context ctx) {
        //實(shí)現(xiàn)文法中與終結(jié)符有關(guān)的解釋操作
    }
}

// 非終結(jié)符表達(dá)式
public class NonterminalExpression extends AbstractExpression {
    @Override
    public void interpret(Context ctx) {
        //實(shí)現(xiàn)文法中與非終結(jié)符有關(guān)的解釋操作
    }
}

// 上下文環(huán)境類(lèi),包含解釋器之外的全局信息
public class Context {
}

// 客戶(hù)類(lèi)
public class Client {
    public static void main(String[] args) {
        //根據(jù)文法對(duì)特定句子構(gòu)建抽象語(yǔ)法樹(shù)后解釋
    }
}

簡(jiǎn)單實(shí)現(xiàn)

需求:比如算數(shù)表達(dá)式 m + n + p。代表數(shù)字的m鲸拥、n拐格、p三個(gè)字符看成終結(jié)符號(hào),+ 看做非終結(jié)符號(hào)刑赶。

  1. 抽象的算術(shù)運(yùn)算解釋器禁荒,為所有解釋器共性的提取

    public abstract class ArithmeticExpression {
        /**
         * 抽象的解析方法
         * 具體的解析邏輯由具體的子類(lèi)實(shí)現(xiàn)
         * @return 解析得到具體的值
         */
        public abstract int interpret();
    }
    
  2. 數(shù)字解釋器,僅僅為了解釋數(shù)字

    public class NumExpression extends ArithmeticExpression{
        private int num;
    
        public NumExpression(int num) {
            this.num = num;
        }
    
        @Override
        public int interpret() {
            return num;
        }
    }
    
  3. 運(yùn)算符號(hào)抽象解釋器角撞,為所有運(yùn)算符號(hào)解釋器共性的提取

    public abstract class OperatorExpression extends ArithmeticExpression {
        //聲明兩個(gè)成員變量存儲(chǔ)運(yùn)算符號(hào)兩邊的數(shù)字解釋器
        protected ArithmeticExpression exp1, exp2;
    
        public OperatorExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
            this.exp1 = exp1;
            this.exp2 = exp2;
        }
    }
    
  4. 加法運(yùn)算抽象解釋器

    public class AdditionExpression extends OperatorExpression {
        public AdditionExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
            super(exp1, exp2);
        }
    
        @Override
        public int interpret() {
            return exp1.interpret() + exp2.interpret();
        }
    }
    
  5. 處理與解釋相關(guān)的一些業(yè)務(wù)

    public class Calculator {
        //聲明一個(gè)Stack棧存儲(chǔ)并操作所有相關(guān)的解釋器
        private Stack<ArithmeticExpression> mExpStack = new Stack<>();
    
        public Calculator(String expression) {
            //聲明兩個(gè)TerminalExpression類(lèi)型的臨時(shí)變量呛伴,存儲(chǔ)運(yùn)算符左右兩邊的數(shù)字解釋器
            ArithmeticExpression exp1, exp2;
    
            String[] elements = expression.split(" ");
    
            //循環(huán)遍歷表達(dá)式元素?cái)?shù)組
            for (int i = 0; i < elements.length; i++) {
                //判斷運(yùn)算符號(hào)
                switch (elements[i].charAt(0)) {
                    case '+':   //如果是加號(hào)
                        //將棧中的解釋器彈出作為運(yùn)算符號(hào)右邊的解釋器
                        exp1 = mExpStack.pop();
                        //同時(shí)將運(yùn)算符號(hào)數(shù)組下標(biāo)下一個(gè)元素構(gòu)造為一個(gè)數(shù)字解釋器
                        exp2 = new NumExpression(Integer.valueOf(elements[++i]));
                        //通過(guò)尚明兩個(gè)數(shù)字解釋器構(gòu)造加法運(yùn)算解釋器
                        mExpStack.push(new AdditionExpression(exp1, exp2));
                        break;    
                    default:    //如果是數(shù)字
                        //直接構(gòu)造數(shù)字解釋器并壓入棧
                        mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
                        break;
                }
            }
        }
    
        public int calculate() {
            return mExpStack.pop().interpret();
        }
    }
    
  6. 客戶(hù)類(lèi)

    public class Client {
        public static void main(String[] args) {
            Calculator calculator = new Calculator("1 + 2 + 3 + 10");
            System.out.println(calculator.calculate());
        }
    }
    

此時(shí)只是定義了加法運(yùn)算,如果需要增加減法運(yùn)算谒所,則可以在 Calculator 中增加以下分支

case '-':   //如果是減號(hào)
    exp1 = mExpStack.pop();
    exp2 = new NumExpression(Integer.valueOf(elements[++i]));
    mExpStack.push(new SubtractionExpression(exp1, exp2));
    break;

此時(shí)热康,在 Client 中就可以開(kāi)始使用了

public class Client {
    public static void main(String[] args) {
        Calculator calculator = new Calculator("1 - 2 - 3 + 10");
        System.out.println(calculator.calculate());
    }
}

Android 源碼中的實(shí)現(xiàn)

AndroidManifest.xml 配置文件的讀取。

總結(jié)

  1. 優(yōu)點(diǎn)

    靈活的擴(kuò)展性劣领,當(dāng)我們相對(duì)文法規(guī)則進(jìn)行擴(kuò)展延伸時(shí)姐军,只需要增加相應(yīng)的非終結(jié)符解釋器,并在構(gòu)建抽象語(yǔ)法樹(shù)時(shí)尖淘,使用到新增的解釋器對(duì)象進(jìn)行具體的解釋即可奕锌。

  2. 缺點(diǎn)

    每一條文法都可以對(duì)應(yīng)至少一個(gè)解釋器,其會(huì)生成大量的類(lèi)村生,導(dǎo)致后期維護(hù)困難惊暴;同時(shí),對(duì)于復(fù)雜的文法趁桃,構(gòu)建其抽象語(yǔ)法樹(shù)會(huì)顯得異常繁瑣辽话,甚至有可能會(huì)出現(xiàn)需要構(gòu)建多棵抽象語(yǔ)法樹(shù)的情況,因此卫病,對(duì)于復(fù)雜的文法并不推薦使用解釋器模式油啤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蟀苛,隨后出現(xiàn)的幾起案子益咬,更是在濱河造成了極大的恐慌,老刑警劉巖帜平,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幽告,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡罕模,警方通過(guò)查閱死者的電腦和手機(jī)窖铡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)墓懂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人挥等,你說(shuō)我怎么就攤上這事蝶念∨淄螅” “怎么了芋绸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)担敌。 經(jīng)常有香客問(wèn)我摔敛,道長(zhǎng),這世上最難降的妖魔是什么全封? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任马昙,我火速辦了婚禮,結(jié)果婚禮上刹悴,老公的妹妹穿的比我還像新娘行楞。我一直安慰自己,他們只是感情好土匀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布子房。 她就那樣靜靜地躺著,像睡著了一般就轧。 火紅的嫁衣襯著肌膚如雪证杭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天妒御,我揣著相機(jī)與錄音解愤,去河邊找鬼。 笑死乎莉,一個(gè)胖子當(dāng)著我的面吹牛琢歇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梦鉴,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼李茫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了肥橙?” 一聲冷哼從身側(cè)響起魄宏,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎存筏,沒(méi)想到半個(gè)月后宠互,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椭坚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年予跌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片善茎。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡券册,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烁焙,我是刑警寧澤航邢,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站骄蝇,受9級(jí)特大地震影響膳殷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜九火,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一赚窃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岔激,春花似錦考榨、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至震叙,卻和暖如春掀鹅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背媒楼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工乐尊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人划址。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓扔嵌,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親夺颤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痢缎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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

  • 1 場(chǎng)景問(wèn)題# 1.1 讀取配置文件## 考慮這樣一個(gè)實(shí)際的應(yīng)用,維護(hù)系統(tǒng)自定義的配置文件世澜。 幾乎每個(gè)實(shí)際的應(yīng)用系...
    七寸知架構(gòu)閱讀 3,109評(píng)論 2 56
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理独旷,服務(wù)發(fā)現(xiàn),斷路器寥裂,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 解釋器模式在我看來(lái)嵌洼,應(yīng)用范圍很小,我想了很久封恰,想舉一個(gè)不是加減乘除運(yùn)算的例子出來(lái)麻养,但是很難......在設(shè)計(jì)模式一...
    Mock2052閱讀 945評(píng)論 0 1
  • 引子 解釋器模式應(yīng)該是一個(gè)很少會(huì)用到的模式,也不太好理解诺舔,用例子的方式來(lái)講解吧鳖昌。 定義 解釋器模式是類(lèi)的行為模式备畦。...
    silentleaf閱讀 3,589評(píng)論 1 4
  • 自駕羌塘7天路書(shū)全程:2200公里耗時(shí):7天 【Day1:拉薩-班戈縣】 ★里程:370公里 ★路況:全程柏油路 ...
    天涯何處不天涯閱讀 1,243評(píng)論 0 1