前言

Android的设计模式系列文章介绍,欢迎关注,持续更新中:

1.定义

给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

2.介绍

解释器模式属于行为型模式。

解释器模式提供了一种解释语言的语法或表达式的方式。

解释器模式实际开发中很少用到。

3.UML类图

解释器模式UML类图.jpg

角色说明:

AbstractExpression(抽象表达式):定义一个抽象的解释方法,其具体的实现在各个具体的子类解释器中完成。

TerminalExpression(终结符表达式):实现对文法中与终结符有关的解释操作。

NonterminalExpression(非终结符表达式):实现对文法中的非终结符有关的解释操作。

Context(环境角色):包含解释器之外的全部信息。

Client(客户端角色):解析表达式,构建抽象语法树,执行具体的解释操作等。

4.实现

以加减法的实现为例,我们实现下面表达式的解释并输出结果,为了方便解释,在表达式中介加了空格方便处理。

a = 1024

b = 512

a + b

a - b

4.1 创建抽象表达式

public abstract class ArithmeticExpression {//抽象算术表达式

public abstract Object interpret(Context context);//抽象解释方法

}

4.2 终结符表达式

从上面的表达式可以看出,终结符有两种,一种是数字,另外一种是变量。

//数字表达式,用来解释数字

public class NumExpression extends ArithmeticExpression {

private String strNum;

public NumExpression(String strNum) {

this.strNum = strNum;

}

@Override

public Integer interpret(Context context) {//解释数字

return Integer.parseInt(strNum);

}

}

//变量表达式,用来解释变量

class VarExpression extends ArithmeticExpression {

private String var;

public VarExpression(String var) {

this.var = var;

}

@Override

public String interpret(Context context) {//解释变量

return var;

}

}

4.3 创建非终结符表达式

上面的表达式有三种非终结符,分别是+号、-号和=号。

//加法表达式,用来解释加法,如a+b

public class AddExpression extends ArithmeticExpression {

private ArithmeticExpression left, right;//加号左右两边的内容

public AddExpression(ArithmeticExpression left, ArithmeticExpression right) {

this.left = left;

this.right = right;

}

@Override

public Integer interpret(Context context) {//解释加法表达式的结果,即算出left+right的结果

return context.get((String) left.interpret(context)) + context.get((String) right.interpret(context));

}

}

//减法表达式,用来解释减法,如a-b

public class SubExpression extends ArithmeticExpression {

private ArithmeticExpression left, right;//减号左右两边的内容

public SubExpression(ArithmeticExpression left, ArithmeticExpression right) {

this.left = left;

this.right = right;

}

@Override

public Integer interpret(Context context) {//解释减法表达式的结果,即算出left-right的结果

return context.get((String) left.interpret(context)) - context.get((String) right.interpret(context));

}

}

//等号表达式,用来解释变量赋值,如a=1024

public class EqualExpression extends ArithmeticExpression {

private ArithmeticExpression left, right;//等号左右两边的内容

public EqualExpression(ArithmeticExpression left, ArithmeticExpression right) {

this.left = left;

this.right = right;

}

@Override

public Object interpret(Context context) {//解释等号表达式的结果,并将结果保存到context,变量名为key,值为value

context.put((String) left.interpret(context), (int) right.interpret(context));

return null;

}

}

4.4 创建环境角色

创建环境主要包含解释器之外的全部信息,这里用来保存变量以及其值。

public class Context {

Map mMap = new HashMap<>();//使用HashMap来保存结果

public void put(String key, int value) {

mMap.put(key, value);

}

public int get(String key) {

return (int) mMap.get(key);

}

}

4.5 创建客户端角色:

客户端角色主要负责解析表达式,构建抽象语法树,执行具体的解释操作等。

public class Calculator {//计算器类

Context mContext = new Context();

private ArithmeticExpression mExpression;

public void read(String expression) {//读取表达式

String[] split = expression.split(" ");//表达式以空格隔开,方便拆分

switch (split[1]) {//根据不同符号去执行具体的解析操作

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() {//计算结果

return (int) mExpression.interpret(mContext);

}

}

4.6 客户端测试:

public void test() {

Calculator calculator = new Calculator();

calculator.read("a = 1024");//读取表达式

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());//计算结果

calculator.read("a - b");

System.out.println("a - b = " + calculator.calculate());

}

输出结果:

a = 1024

b = 512

a + b = 1536

a - b = 512

5. 应用场景

简单的语法需要解释时,如解释一个sql语句。

一些重复发生的问题,比如加减乘除四则运算,但是公式每次都不同,有时是a+b-cd,有时是ab+c-d等,公式千变万化,但是都是由加减乘除四个非终结符来连接的,这时我们就可以使用解释器模式。

6. 优点

灵活的扩展性,想扩展语法规则时只需新增新的解释器就可以了。如上面的例子中,想增加乘除法,只想增加相应的解释类,并增加相应的表达式解释操作即可。

7. 缺点

每一个文法都至少对应一个解释器,会产生大量的类,难于维护。

解释器模式由于大量使用循环和递归,需要考虑效率的问题,而且调试也不方便。

对于复杂的文法,构建其抽象语法树会显得异常繁琐。

所以不推荐在重要的模块中使用解释器模式,维护困难。

8. Android中的源码分析

对于AndroidManifest.xml这个文件,我们是相当熟悉。实际上AndroidManifest.xml是由PackageManagerService使用了PackageParser这个类来解释的,这里面就用到了解释器模式。对于AndroidManifest.xml中的每一个标签,都有对应的类去保存相应的信息。

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标签

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 {

//其他代码略

}

}

从上面代码可以看到,就是对各个标签的内容进行解释。我们再来看看parseBaseApplication这个方法,这个是对Application进行解释。

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等标签的解释,activity的具体解释在parseActivity这个方法里面,有兴趣的可以自行去看下,这里就不细说了,同时可以看到receiver也是在parseActivity这个方法中解释。

解释器android,Android的设计模式-解释器模式相关推荐

  1. android工厂模式源码,Android源码设计模式——工厂模式

    工厂模式也是为了构建一个新的对象,它是创建型模式的一种. Android源码设计模式--Build模式(应用:AlertDialog源码分析) 上述是之前的Build模式,也是创建型模式一种,不懂的小 ...

  2. Android中的设计模式-状态模式

    原文出处:http://www.linuxidc.com/Linux/2015-04/116013.htm 状态模式说明 "状态模式允许一个对象在其内部状态改变的时候改变其行为.这个对象看上 ...

  3. Android中的设计模式-桥梁模式

    "假舆马者,非利足也,而致千里:假舟楫者,非能水也,而绝江河.君子生非异也,善假于物也."--荀子<劝学>. 美国好莱坞电影有<蜘蛛侠>.<蝙蝠侠&g ...

  4. Python设计模式-解释器模式

    Python设计模式-解释器模式 代码基于3.5.2,代码如下; #coding:utf-8 #解释器模式class PlayContext():play_text = Noneclass Expre ...

  5. Java设计模式(备忘录模式-解释器模式-状态模式-策略模式-职责链模式)

    Java设计模式Ⅶ 1.备忘录模式 1.1 备忘录模式概述 1.2 代码理解 2.解释器模式 2.1 解释器模式概述 3.状态模式 3.1 状态模式概述 3.2 代码理解 4.策略模式 4.1 策略模 ...

  6. Android中的设计模式之代理模式

    参考 <设计模式:可复用面向对象软件的基础 >4.7 Proxy 代理--对象结构型模式 <Android源码设计模式解析与实战>第18章 编程好帮手--代理模式 意图 为其它 ...

  7. android 构建者设计模式,Android中的设计模式之构建者模式

    参考 <设计模式:可复用面向对象软件的基础 >3.2 Builder 生成器--对象创建型模式 <Android源码设计模式解析与实战>第3章 Builder模式 意图 将一个 ...

  8. PHP设计模式——解释器模式

    声明:本系列博客参考资料<大话设计模式>,作者程杰. 解释器模式:Given a language, define arepresentation for its grammar alon ...

  9. 当Android遇上设计模式之代理(Proxy)模式

    文章目录 1. 代理模式 1.1 代码实现 1.2 使用场景 2. 静态代理与动态代理 设计模式六大原则: 单一职责原则:就一个类仅有一个引起它变化的原因,即类承担的职责单一性: 开放封闭原则:类.模 ...

  10. 初识设计模式 - 解释器模式

    简介 在某些情况下,为了更好地描述某一些特定类型的问题,我们可以创建一种新的语言,这种语言拥有自己的表达式和结构,即文法规则. 解释器设计模式(Interpreter Design Pattern)描 ...

最新文章

  1. Http://selboo.com.cn
  2. python中如何定义颜色_Python图像处理之颜色的定义与使用分析
  3. TCP网络编程中connect()、listen()和accept()三者之间的关系
  4. 解决Eclipse中文乱码
  5. php小结,PHP编程小结
  6. python正则表达式中的转义字符_详解python中正则表达式的反斜线的转义功能
  7. c语言常用二个标准库函数
  8. 软件开发计划_敏捷软件开发实践:估算与计划读书笔记123第21章 关于计划的沟通...
  9. (Mark)JS中的上下文
  10. mongoDB高级查询
  11. hdu 5919--Sequence II(主席树--求区间不同数个数+区间第k大)
  12. Linux音频驱动-ALSA概述
  13. java集合复习笔记-java集合继承关系图
  14. DBC2000是什么?DBC2000数据库文件超详细讲解
  15. excel怎么设置自动计算_用Excel,做一套税费计算表|自动计算 自动汇总 四个税种【梓晖】...
  16. vt功能对计算机有影响吗,win7怎么开启vt模拟器?电脑开vt有什么坏处?
  17. 集合——数组容器笔记
  18. Z3735d android x86,首款搭载Z3735处理器 神秘平板被曝光
  19. 【TA-霜狼_may-《百人计划》】图形3.7.2 command buffer简
  20. MATLAB分析各类建筑能耗与环境温度关系

热门文章

  1. OpenscenGraph中控制swapbuffer的方法(用于多机大屏幕同步显示机制)
  2. 不要用偏执毁掉一个产业
  3. java多张图片合成一张_1分钟学会“全景照片”拍摄技巧,从单反拍摄到PS合成,收藏备用...
  4. php修改学生信息代码_值得收藏的CRM软件客户管理系统(包括JAVA/PHP)
  5. Linux上Svn环境搭建
  6. Java BigDecimal intValue()方法与示例
  7. android 默认浏览器 视频播放 二维码,Android调用系统默认浏览器访问的方法
  8. 智能循迹避障小车C语言程序编写思路,基于单片机的智能小车红外避障循迹系统设计与制作...
  9. mysql8安装目录linux7.5_Linux系统下 MySQL 5.7和8.0 版本安装指南
  10. 中怎么撤回消息_微信消息撤回也能看到,这个开源神器牛x!语音、图片、文字都支持!...