Android編程設(shè)計(jì)模式之解釋器模式詳解
本文實(shí)例講述了Android編程設(shè)計(jì)模式之解釋器模式。分享給大家供大家參考,具體如下:
一、介紹
解釋器模式(Interpreter Pattern)是一種用的比較少的行為型模式,其提供了一種解釋語言的語法或表達(dá)式的方式,該模式定義了一個(gè)表達(dá)式接口,通過該接口解釋一個(gè)特定的上下文。在這么多的設(shè)計(jì)模式中,解釋器模式在實(shí)際運(yùn)用上相對(duì)來說要少很多,因?yàn)槲覀兒苌贂?huì)自己去構(gòu)造一個(gè)語言的文法。雖然如此,既然它能夠在設(shè)計(jì)模式中有一席之位,那么必定有它的可用之處。
二、定義
給定一個(gè)語言,定義它的文法的一種表示,并定義一個(gè)解釋器,該解釋器使用該表示來解釋語言中的句子。(其中語言就是我們需要解釋的對(duì)象,文法就是這個(gè)語言的規(guī)律,解釋器就是翻譯機(jī),通過文法來翻譯語言。)
三、使用場(chǎng)景
如果某個(gè)簡(jiǎn)單的語言需要解釋執(zhí)行而且可以將該語言中的語句表示為一個(gè)抽象的語法樹時(shí)可以考慮使用解釋器模式。
在某些特定的領(lǐng)域出現(xiàn)不斷重復(fù)的問題時(shí),可以將該領(lǐng)域的問題轉(zhuǎn)化為一種語法規(guī)則下的語句,然后構(gòu)建解釋器來解釋該語句。
四、解釋器模式的UML類圖
UML類圖:

角色介紹:
AbstractExpression:抽象表達(dá)式,聲明一個(gè)抽象的解釋操作父類,并定義一個(gè)抽象的 interpret() 解釋方法,其具體的實(shí)現(xiàn)在各個(gè)具體的子類解釋器中完成。
TerminalExpression:終結(jié)符表達(dá)式,實(shí)現(xiàn)了抽象表達(dá)式角色所要求的接口,主要是一個(gè)interpret()方法;文法中的每一個(gè)終結(jié)符都有一個(gè)具體終結(jié)表達(dá)式與之相對(duì)應(yīng)。比如有一個(gè)簡(jiǎn)單的公式R=R1+R2,在里面R1和R2就是終結(jié)符,對(duì)應(yīng)的解析R1和R2的解釋器就是終結(jié)符表達(dá)式。
NonterminalExpression:非終結(jié)符表達(dá)式,文法中的每一條規(guī)則都需要一個(gè)具體的非終結(jié)符表達(dá)式,非終結(jié)符表達(dá)式一般是文法中的運(yùn)算符或者其他關(guān)鍵字,比如公式R=R1+R2中,“+”就是非終結(jié)符,解析“+”的解釋器就是一個(gè)非終結(jié)符表達(dá)式。
Context:上下文環(huán)境類,這個(gè)角色的任務(wù)一般是用來存放文法中各個(gè)終結(jié)符所對(duì)應(yīng)的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些信息需要存放到環(huán)境角色中,很多情況下我們使用Map來充當(dāng)環(huán)境角色就足夠了。
Client:客戶類,解析表達(dá)式,構(gòu)建抽象語法樹,執(zhí)行具體的解釋操作等。
通用代碼如下:
/**
* 抽象表達(dá)式
*/
public abstract class AbstractExpression {
/**
* 抽象的解析方法
* @param context 上下文環(huán)境對(duì)象
*/
public abstract void interpret(Context context);
}
/**
* 終結(jié)符表達(dá)式
*/
public class TerminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
//實(shí)現(xiàn)文法中與終結(jié)符有關(guān)的解釋操作
}
}
/**
* 非終結(jié)符表達(dá)式
*/
public class NonterminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
//實(shí)現(xiàn)文法中與非終結(jié)符有關(guān)的解釋操作
}
}
/**
* 上下文環(huán)境類
*/
public class Context {
}
/**
* 客戶類
*/
public class Client {
public static void main(String[] args) {
//根據(jù)文法對(duì)特定句子構(gòu)建抽象語法樹后解釋
}
}
五、簡(jiǎn)單實(shí)現(xiàn)
我們使用解釋器模式對(duì)“m+n+p”這個(gè)表達(dá)式進(jìn)行解釋,那么代表數(shù)字的m、n和p就可以看成終結(jié)符號(hào),而“+”這個(gè)運(yùn)算符號(hào)可以當(dāng)做非終結(jié)符號(hào)。
抽象的算數(shù)運(yùn)算解釋器:
public abstract class ArithemticExpression {
/**
* 抽象的解析方法
* 具體的解析邏輯由具體的子類實(shí)現(xiàn)
*
* @return 解析得到具體的值
*/
public abstract int interpreter();
}
數(shù)字解釋器:
public class NumExpression extends ArithemticExpression{
private int num;
public NumExpression(int num){
this.num = num;
}
@Override
public int interpreter() {
return num;
}
}
運(yùn)算符號(hào)解釋器:
public abstract class OperatorExpression extends ArithemticExpression{
protected ArithemticExpression exp1, exp2;
public OperatorExpression(ArithemticExpression exp1, ArithemticExpression exp2){
this.exp1 = exp1;
this.exp2 = exp2;
}
}
具體的加法運(yùn)算符解釋器:
public class AdditionExpression extends OperatorExpression{
public AdditionExpression(ArithemticExpression exp1,
ArithemticExpression exp2) {
super(exp1, exp2);
}
@Override
public int interpreter() {
return exp1.interpreter() + exp2.interpreter();
}
}
處理解釋器:
public class Calculator {
//聲明一個(gè)Stack棧儲(chǔ)存并操作所有相關(guān)的解釋器
private Stack<ArithemticExpression> mExpStack = new Stack<ArithemticExpression>();
public Calculator(String expression){
//聲明兩個(gè)ArithemticExpression類型的臨時(shí)變量,儲(chǔ)存運(yùn)算符左右兩邊的數(shù)字解釋器
ArithemticExpression exp1,exp2;
//根據(jù)空格分割表達(dá)式字符串(比如1 + 2 + 3 + 4)
String[] elements = expression.split(" ");
/*
* 遍歷表達(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.parseInt(elements[++i]));
//通過上面的兩個(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;
}
}
}
/**
* 計(jì)算結(jié)果
*
* @return 最終的計(jì)算結(jié)果
*/
public int calculate(){
return mExpStack.pop().interpreter();
}
}
調(diào)用:
public class Client {
public static void main(String[] args) {
Calculator c = new Calculator("22 + 553 + 83 + 5");
System.out.println("計(jì)算結(jié)果:"+c.calculate());
}
}
結(jié)果:
計(jì)算結(jié)果:663
如果相加如減法的操作,在Calculator中加入相應(yīng)判斷即可:
public class SubtractionExpression extends OperatorExpression{
public SubtractionExpression(ArithemticExpression exp1,
ArithemticExpression exp2) {
super(exp1, exp2);
}
@Override
public int interpreter() {
return exp1.interpreter() - exp2.interpreter();
}
}
Calculator中加入:
case '-': exp1 = mExpStack.pop(); exp2 = new NumExpression(Integer.parseInt(elements[++i])); mExpStack.push(new SubtractionExpression(exp1, exp2)); break;
從上面可以看出解釋器模式很靈活,他將復(fù)雜問題可以簡(jiǎn)單化、模塊化、分離實(shí)現(xiàn)、解釋執(zhí)行。
六、Android源碼中解釋器模式
1、PackageParser
PackageParser是對(duì)AndroidManifest.xml配置文件進(jìn)行讀取的,具體原理參考:解析AndroidManifest原理
七、總結(jié)
優(yōu)點(diǎn):
最大的優(yōu)點(diǎn)使其靈活的擴(kuò)展性,當(dāng)我們想對(duì)文法規(guī)則進(jìn)行擴(kuò)展延伸時(shí),只需要增加相應(yīng)的非終結(jié)符解釋器,并在構(gòu)建抽象語法樹時(shí),使用到新增的解釋器對(duì)象進(jìn)行具體的解釋即可,非常方便。
缺點(diǎn):
每個(gè)語法都要產(chǎn)生一個(gè)非終結(jié)符表達(dá)式,語法規(guī)則比較復(fù)雜時(shí),就可能產(chǎn)生大量的類文件,為維護(hù)帶來了非常多的麻煩。
解釋器模式由于使用了大量的循環(huán)和遞歸,效率是個(gè)問題,特別是用于解析復(fù)雜、冗長(zhǎng)的語法時(shí),效率是難以忍受的。
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android開發(fā)入門與進(jìn)階教程》、《Android調(diào)試技巧與常見問題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
Flutter簡(jiǎn)潔實(shí)用的圖片編輯器的實(shí)現(xiàn)
本文主要介紹了Flutter簡(jiǎn)潔實(shí)用的圖片編輯器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
Android實(shí)現(xiàn)pdf在線預(yù)覽或本地預(yù)覽的方法
下面小編就為大家分享一篇Android實(shí)現(xiàn)pdf在線預(yù)覽或本地預(yù)覽的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01
Android使用PhotoView實(shí)現(xiàn)圖片雙擊放大單擊退出效果
這篇文章主要為大家詳細(xì)介紹了Android使用PhotoView實(shí)現(xiàn)圖片雙擊放大單擊退出效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
android使用surfaceview+MediaPlayer播放視頻
這篇文章主要為大家詳細(xì)介紹了android使用surfaceview+MediaPlayer播放視頻,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
Android便攜式熱點(diǎn)的開啟狀態(tài)檢測(cè)和SSID的獲取方法
WIFI熱點(diǎn)的開啟狀態(tài)和開啟后的SSID如何獲取呢?接下來通過本文給大家分享Android便攜式熱點(diǎn)的開啟狀態(tài)檢測(cè)和SSID的獲取方法,需要的朋友參考下吧2017-01-01
新版Android Studio3.6找不到R.java怎么處理
這篇文章主要介紹了新版Android Studio3.6找不到R.java怎么處理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Android 優(yōu)雅的實(shí)現(xiàn)通用格式化編輯
這篇文章主要介紹了Android 優(yōu)雅的實(shí)現(xiàn)通用格式化編輯,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03
Android實(shí)現(xiàn)將一個(gè)Activity設(shè)置成窗口樣式的方法
這篇文章主要介紹了Android實(shí)現(xiàn)將一個(gè)Activity設(shè)置成窗口樣式的方法,涉及Android的窗口樣式設(shè)置與布局技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-02-02

