Android中的设计模式之解释器模式
参考
- 《设计模式:可复用面向对象软件的基础 》5.3 Interpreter 解释器 类行为型模式
- 《Android源码设计模式解析与实战》第10章 化繁为简的翻译机--解释器模式
意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器适用该表示来解释语言中的句子。
适用场景
当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:
- 该文法简单对于复杂的文法,文法的类层次变得庞大而又无法管理。
- 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换为另一种形式。
非终结符号与终止符号
例:
S ::= abA*ef A ::= cd
符号“::=”表示推导;符号“*”表示闭包,意思就是符号A可以有0或有N个重复;S和A称为非终结符号,因为他们能推导出式子右边的表达式,同时又因为整个推导式是从S出发的,因此,这个S也称为初始符号;而abef和cd这些字符不能再被推导我们称之为终结符号。
结构
- AbstractExpression 抽象表达式,声明一个抽象的解释操作父类,并定义了一个抽象的解释方法,其具体的实现在各个具体的子类解释器中完成。
- TeminalExpression 终结符表达式,实现文法中与终结符有关的解释操作。
- NonterminalExpression 非终结符表达式,实现文法中与非终结符有关的解释操作。
- Context 上下文环境类,包含解释器之外的全局信息。
- Client 客户端类,解析表达式,构建抽象语法树,执行具体的解释表达操作等。
优点
灵活的扩展性,当我们想对文法规则进行扩展延伸时,只需要增加相应的非终结符解释器,并在构建抽象语法树时,使用到新增的解释器对象进行具体的解释即可,比较方便。
缺点
每一条文法都对应一个解释器,会生成大量类,导致后期维护困难。同时,对于过于复杂的文法,构建其抽象语法树会显得异常繁琐,因此,对于复杂的文法并不推荐使用解释器模式。
例子1
描述
表达式“m+n+p”,如果我们使用解释器模式对该表达式进行解释,那么代表数字的m,n,和p三个字母我们就可以看成是终结符号,而“+”这个算术运算符号则可当作非终结符,同时我们可以先创建一个抽象解释器表示数学运算。
结构
代码实现
/** * 算术运算解释器抽象类 * @author newtrekWang * @email wangjiaxing20160101@gmail.com * @time 2018/8/19 23:22 */ public abstract class AthmeticExpression { /** * 抽象的解析方法 * @return 解析得到的值 */ abstract int interpreter(); } /** * 数字解释器,只为了解释数字 * @author newtrekWang * @email wangjiaxing20160101@gmail.com * @time 2018/8/19 23:24 */ public class NumExpression extends AthmeticExpression { private int num; public NumExpression(int num){ this.num = num; } @Override int interpreter() { return num; } } /** * 运算符解释器 * @author newtrekWang * @email wangjiaxing20160101@gmail.com * @time 2018/8/19 23:27 */ public abstract class OperatorExpression extends AthmeticExpression { /** * 运算符两边的表达式 */ protected AthmeticExpression exp1,exp2; public OperatorExpression(AthmeticExpression exp1, AthmeticExpression exp2) { this.exp1 = exp1; this.exp2 = exp2; } } /** * 加法解释器 * @author newtrekWang * @email wangjiaxing20160101@gmail.com * @time 2018/8/19 23:29 */ public class AdditionExpressoin extends OperatorExpression { public AdditionExpressoin(AthmeticExpression exp1, AthmeticExpression exp2) { super(exp1, exp2); } /** * 具体解释+符号 * @return 解释结果 */ @Override int interpreter() { return exp1.interpreter()+exp2.interpreter(); } } /** * 计算器类 * @author newtrekWang * @email wangjiaxing20160101@gmail.com * @time 2018/8/19 23:30 */ public class Calculator { /** * 用一个栈存储并操作所有相关的解释器 */ private Stack<AthmeticExpression> mExpStack = new Stack<>(); public Calculator(String expression){ AthmeticExpression exp1,exp2; // 以空格分开元素 String[] elements = expression.split(" "); for (int i = 0;i<elements.length;i++){ switch (elements[i].charAt(0)){ // 如果为‘+’ case '+': // 将栈中的解释器弹出作为运算符左边的解释器 exp1 = mExpStack.pop(); // 同时将运算符数组下标下一个元素构造为一个数字解释器 exp2 = new NumExpression(Integer.valueOf(elements[++i])); mExpStack.push(new AdditionExpressoin(exp1,exp2)); break; default: // 如果为数字 mExpStack.push(new NumExpression(Integer.valueOf(elements[i]))); break; } } } /** * 最终结算结果 * @return */ public int calculate(){ return mExpStack.pop().interpreter(); } } public static void main(String[] args){ Calculator calculator = new Calculator("3 + 8 + 2"); System.out.println(calculator.calculate()); }
输出结果:
13
应用例子2 Android源码中的PackageParser
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Fluwx:微信SDK在Flutter上的实现
前言 随着 Flutter越来越火热,我相信越来越多的小伙伴都跃跃欲试。但是一个很重要的问题是,很多第三方 SDK,如微信SDK,都无法在Flutter上直接使用。所以,我这几天开发了一个微信SDK的插件,希望能够一定程度上帮助到大家。 Fluwx要做什么 分享 登录 支付 这是Fluwx的目标。现在Fluwx仍在开发阶段,android分享部分已经完成,ios部分还在持续开发。如果你想也成为Fluwx的开发者,可以给我留言。 需要准备的 使用Fluwx之前,强烈建议先阅读微信SDK官方文档, 这有助于你使用Fluwx。Fluwx的api字段名称基本和官方的字段名称是一致的。 引入 在pubspec.yaml文件中添加如下代码: dependencies: fluwx: ^0.0.1 初始化 Fluwx.registerApp(RegisterModel(appId: "your app id", doOnAndroid: true, doOnIOS: true)); appId:在微信平台申请的appId。 doOnAndroid:是否在android平台上执行此操作。 doOnIO...
- 下一篇
Android 几种异步方式,解决主线程中遇到的卡顿
起因: 当我们的UI越来越复杂的时候,或者说某个业务需要大量的计算的时候,我们的主线程会消耗大量的资源去计算,这个时候,我们的Activity或者说fragmemt等UI页面就会出现卡顿,乃至ANR。总结一下,就是我们直接在主线程(UI线程)中,做耗时操作,就会造成卡顿,甚至ANR 解决方案: 1.优化耗时的计算,提高算法,利用缓存等数据;这种方式,一般带来的提升在App这种场景中微乎其微,只有在大规模的并发场景中才会体现出效果(服务器后台服务中),打个比方,你存一年1W块钱的定期,一年利息才200多块,当你存1000W的时候,一年利息就有20多W,这种效果才明显(手动滑稽) 2.利用异步的方式,简单来说,开启另外一个线程去做耗时操作,利用CPU的多线程模式,这样我们的主线程就不会卡顿在耗时操作中 异步的方式: 1.直接使用继承Thread类或者实现Runable接口(和主线程通信还得使用handler) 2.AsyscTask(它的原理主要是利用线程池,各个历史版本系统版本可能会有不同的缺陷) 3.利用Handler,Message,Looper(主线程默认开启了Looper) 4....
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS关闭SELinux安全模块
- CentOS8编译安装MySQL8.0.19
- CentOS7设置SWAP分区,小内存服务器的救世主
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池