解释器android,Android的设计模式-解释器模式
前言
Android的設(shè)計模式系列文章介紹,歡迎關(guān)注,持續(xù)更新中:
1.定義
給定一門語言,定義它的文法的一種表示,并定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。
2.介紹
解釋器模式屬于行為型模式。
解釋器模式提供了一種解釋語言的語法或表達(dá)式的方式。
解釋器模式實際開發(fā)中很少用到。
3.UML類圖
解釋器模式UML類圖.jpg
角色說明:
AbstractExpression(抽象表達(dá)式):定義一個抽象的解釋方法,其具體的實現(xiàn)在各個具體的子類解釋器中完成。
TerminalExpression(終結(jié)符表達(dá)式):實現(xiàn)對文法中與終結(jié)符有關(guān)的解釋操作。
NonterminalExpression(非終結(jié)符表達(dá)式):實現(xiàn)對文法中的非終結(jié)符有關(guān)的解釋操作。
Context(環(huán)境角色):包含解釋器之外的全部信息。
Client(客戶端角色):解析表達(dá)式,構(gòu)建抽象語法樹,執(zhí)行具體的解釋操作等。
4.實現(xiàn)
以加減法的實現(xiàn)為例,我們實現(xiàn)下面表達(dá)式的解釋并輸出結(jié)果,為了方便解釋,在表達(dá)式中介加了空格方便處理。
a = 1024
b = 512
a + b
a - b
4.1 創(chuàng)建抽象表達(dá)式
public abstract class ArithmeticExpression {//抽象算術(shù)表達(dá)式
public abstract Object interpret(Context context);//抽象解釋方法
}
4.2 終結(jié)符表達(dá)式
從上面的表達(dá)式可以看出,終結(jié)符有兩種,一種是數(shù)字,另外一種是變量。
//數(shù)字表達(dá)式,用來解釋數(shù)字
public class NumExpression extends ArithmeticExpression {
private String strNum;
public NumExpression(String strNum) {
this.strNum = strNum;
}
@Override
public Integer interpret(Context context) {//解釋數(shù)字
return Integer.parseInt(strNum);
}
}
//變量表達(dá)式,用來解釋變量
class VarExpression extends ArithmeticExpression {
private String var;
public VarExpression(String var) {
this.var = var;
}
@Override
public String interpret(Context context) {//解釋變量
return var;
}
}
4.3 創(chuàng)建非終結(jié)符表達(dá)式
上面的表達(dá)式有三種非終結(jié)符,分別是+號、-號和=號。
//加法表達(dá)式,用來解釋加法,如a+b
public class AddExpression extends ArithmeticExpression {
private ArithmeticExpression left, right;//加號左右兩邊的內(nèi)容
public AddExpression(ArithmeticExpression left, ArithmeticExpression right) {
this.left = left;
this.right = right;
}
@Override
public Integer interpret(Context context) {//解釋加法表達(dá)式的結(jié)果,即算出left+right的結(jié)果
return context.get((String) left.interpret(context)) + context.get((String) right.interpret(context));
}
}
//減法表達(dá)式,用來解釋減法,如a-b
public class SubExpression extends ArithmeticExpression {
private ArithmeticExpression left, right;//減號左右兩邊的內(nèi)容
public SubExpression(ArithmeticExpression left, ArithmeticExpression right) {
this.left = left;
this.right = right;
}
@Override
public Integer interpret(Context context) {//解釋減法表達(dá)式的結(jié)果,即算出left-right的結(jié)果
return context.get((String) left.interpret(context)) - context.get((String) right.interpret(context));
}
}
//等號表達(dá)式,用來解釋變量賦值,如a=1024
public class EqualExpression extends ArithmeticExpression {
private ArithmeticExpression left, right;//等號左右兩邊的內(nèi)容
public EqualExpression(ArithmeticExpression left, ArithmeticExpression right) {
this.left = left;
this.right = right;
}
@Override
public Object interpret(Context context) {//解釋等號表達(dá)式的結(jié)果,并將結(jié)果保存到context,變量名為key,值為value
context.put((String) left.interpret(context), (int) right.interpret(context));
return null;
}
}
4.4 創(chuàng)建環(huán)境角色
創(chuàng)建環(huán)境主要包含解釋器之外的全部信息,這里用來保存變量以及其值。
public class Context {
Map mMap = new HashMap<>();//使用HashMap來保存結(jié)果
public void put(String key, int value) {
mMap.put(key, value);
}
public int get(String key) {
return (int) mMap.get(key);
}
}
4.5 創(chuàng)建客戶端角色:
客戶端角色主要負(fù)責(zé)解析表達(dá)式,構(gòu)建抽象語法樹,執(zhí)行具體的解釋操作等。
public class Calculator {//計算器類
Context mContext = new Context();
private ArithmeticExpression mExpression;
public void read(String expression) {//讀取表達(dá)式
String[] split = expression.split(" ");//表達(dá)式以空格隔開,方便拆分
switch (split[1]) {//根據(jù)不同符號去執(zhí)行具體的解析操作
case "=":
new EqualExpression(new VarExpression(split[0]), new NumExpression(split[2])).interpret(mContext);
break;
case "+":
mExpression = new AddExpression(new VarExpression(split[0]), new VarExpression(split[2]));
break;
case "-":
mExpression = new SubExpression(new VarExpression(split[0]), new VarExpression(split[2]));
break;
}
}
public int calculate() {//計算結(jié)果
return (int) mExpression.interpret(mContext);
}
}
4.6 客戶端測試:
public void test() {
Calculator calculator = new Calculator();
calculator.read("a = 1024");//讀取表達(dá)式
calculator.read("b = 512");
System.out.println("a = 1024");
System.out.println("b = 512");
calculator.read("a + b");
System.out.println("a + b = " + calculator.calculate());//計算結(jié)果
calculator.read("a - b");
System.out.println("a - b = " + calculator.calculate());
}
輸出結(jié)果:
a = 1024
b = 512
a + b = 1536
a - b = 512
5. 應(yīng)用場景
簡單的語法需要解釋時,如解釋一個sql語句。
一些重復(fù)發(fā)生的問題,比如加減乘除四則運算,但是公式每次都不同,有時是a+b-cd,有時是ab+c-d等,公式千變?nèi)f化,但是都是由加減乘除四個非終結(jié)符來連接的,這時我們就可以使用解釋器模式。
6. 優(yōu)點
靈活的擴(kuò)展性,想擴(kuò)展語法規(guī)則時只需新增新的解釋器就可以了。如上面的例子中,想增加乘除法,只想增加相應(yīng)的解釋類,并增加相應(yīng)的表達(dá)式解釋操作即可。
7. 缺點
每一個文法都至少對應(yīng)一個解釋器,會產(chǎn)生大量的類,難于維護(hù)。
解釋器模式由于大量使用循環(huán)和遞歸,需要考慮效率的問題,而且調(diào)試也不方便。
對于復(fù)雜的文法,構(gòu)建其抽象語法樹會顯得異常繁瑣。
所以不推薦在重要的模塊中使用解釋器模式,維護(hù)困難。
8. Android中的源碼分析
對于AndroidManifest.xml這個文件,我們是相當(dāng)熟悉。實際上AndroidManifest.xml是由PackageManagerService使用了PackageParser這個類來解釋的,這里面就用到了解釋器模式。對于AndroidManifest.xml中的每一個標(biāo)簽,都有對應(yīng)的類去保存相應(yīng)的信息。
8.1 PackageParser的parseBaseApkCommon方法
基于Android 27的源碼,不同版本的源碼方法名可能不一樣。
private Package parseBaseApkCommon(Package pkg, Set acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
//其他代碼略
if (tagName.equals(TAG_APPLICATION)) {
//其他代碼略
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {//解釋application標(biāo)簽
return null;
}
} else if (tagName.equals(TAG_OVERLAY)) {
//其他代碼略
} else if (tagName.equals(TAG_KEY_SETS)) {
if (!parseKeySets(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_GROUP)) {
if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION)) {
if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_TREE)) {
if (!parsePermissionTree(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_USES_PERMISSION)) {
if (!parseUsesPermission(pkg, res, parser)) {
return null;
}
} else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
|| tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
if (!parseUsesPermission(pkg, res, parser)) {
return null;
}
} else if (tagName.equals(TAG_USES_CONFIGURATION)) {
//其他代碼略
} else if (tagName.equals(TAG_USES_FEATURE)) {
//其他代碼略
} else if (tagName.equals(TAG_FEATURE_GROUP)) {
//其他代碼略
} else if (tagName.equals(TAG_USES_SDK)) {
//其他代碼略
} else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
//其他代碼略
} else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
//其他代碼略
} else if (tagName.equals(TAG_INSTRUMENTATION)) {
//其他代碼略
} else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
//其他代碼略
} else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
//其他代碼略
} else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
//其他代碼略
} else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) {
//其他代碼略
} else if (tagName.equals(TAG_SUPPORTS_INPUT)) {//
//其他代碼略
} else if (tagName.equals(TAG_EAT_COMMENT)) {
//其他代碼略
} else if (tagName.equals(TAG_PACKAGE)) {
//其他代碼略
} else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
//其他代碼略
} else if (RIGID_PARSER) {
//其他代碼略
} else {
//其他代碼略
}
}
從上面代碼可以看到,就是對各個標(biāo)簽的內(nèi)容進(jìn)行解釋。我們再來看看parseBaseApplication這個方法,這個是對Application進(jìn)行解釋。
8.2 parseBaseApplication方法
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
//其他代碼略
String tagName = parser.getName();
if (tagName.equals("activity")) {//解釋activity
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
//其他代碼略
} else if (tagName.equals("receiver")) {//解釋receiver
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
true, false);
//其他代碼略
} else if (tagName.equals("service")) {//解釋service
Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
//其他代碼略
} else if (tagName.equals("provider")) {//解釋provider
Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
//其他代碼略
} else if (tagName.equals("activity-alias")) {
Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
//其他代碼略
} else if (parser.getName().equals("meta-data")) {
//其他代碼略
} else if (tagName.equals("static-library")) {
//其他代碼略
} else if (tagName.equals("library")) {
//其他代碼略
} else if (tagName.equals("uses-static-library")) {
if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
return false;
}
} else if (tagName.equals("uses-library")) {
//其他代碼略
} else if (tagName.equals("uses-package")) {
//其他代碼略
} else {
//其他代碼略
}
//其他代碼略
return true;
}
可以看到,上面有對activity、receiver、service等標(biāo)簽的解釋,activity的具體解釋在parseActivity這個方法里面,有興趣的可以自行去看下,這里就不細(xì)說了,同時可以看到receiver也是在parseActivity這個方法中解釋。
總結(jié)
以上是生活随笔為你收集整理的解释器android,Android的设计模式-解释器模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis rua解决库存问题_【150
- 下一篇: cordova 更改app版本_【ios