Android的设计模式-解释器模式
来源:互联网 发布:什么是网络成瘾 编辑:程序博客网 时间:2024/06/03 20:59
前言
Android的设计模式系列文章介绍,欢迎关注,持续更新中:
Android的设计模式-设计模式的六大原则
创建型模式:
Android的设计模式-单例模式
Android的设计模式-建造者模式
Android的设计模式-工厂方法模式
Android的设计模式-简单工厂模式
Android的设计模式-抽象工厂模式
Android的设计模式-原型模式
行为型模式:
Android的设计模式-策略模式
Android的设计模式-状态模式
Android的设计模式-责任链模式
Android的设计模式-观察者模式
Android的设计模式-模板方法模式
Android的设计模式-迭代器模式
Android的设计模式-备忘录模式
Android的设计模式-访问者模式
Android的设计模式-中介者模式
Android的设计模式-解释器模式
1.定义
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
2.介绍
- 解释器模式属于行为型模式。
- 解释器模式提供了一种解释语言的语法或表达式的方式。
- 解释器模式实际开发中很少用到。
3.UML类图
角色说明:
- AbstractExpression(抽象表达式):定义一个抽象的解释方法,其具体的实现在各个具体的子类解释器中完成。
- TerminalExpression(终结符表达式):实现对文法中与终结符有关的解释操作。
- NonterminalExpression(非终结符表达式):实现对文法中的非终结符有关的解释操作。
- Context(环境角色):包含解释器之外的全部信息。
- Client(客户端角色):解析表达式,构建抽象语法树,执行具体的解释操作等。
4.实现
以加减法的实现为例,我们实现下面表达式的解释并输出结果,为了方便解释,在表达式中介加了空格方便处理。
a = 1024b = 512a + ba - 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<String, Object> 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 = 1024b = 512a + b = 1536a - b = 512
5. 应用场景
- 简单的语法需要解释时,如解释一个sql语句。
- 一些重复发生的问题,比如加减乘除四则运算,但是公式每次都不同,有时是a+b-c*d,有时是a*b+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<String> 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的设计模式-单例模式
Android的设计模式-建造者模式
Android的设计模式-工厂方法模式
Android的设计模式-简单工厂模式
Android的设计模式-抽象工厂模式
Android的设计模式-原型模式
行为型模式:
Android的设计模式-策略模式
Android的设计模式-状态模式
Android的设计模式-责任链模式
Android的设计模式-观察者模式
Android的设计模式-模板方法模式
Android的设计模式-迭代器模式
Android的设计模式-备忘录模式
Android的设计模式-访问者模式
Android的设计模式-中介者模式
Android的设计模式-解释器模式
- Android的设计模式-解释器模式
- android设计模式应用--解释器模式
- 设计模式 解释器模式
- 设计模式-解释器模式
- 设计模式:解释器模式
- 设计模式:解释器模式
- 设计模式-解释器模式
- 设计模式-解释器模式
- 设计模式--解释器模式
- 设计模式-解释器模式
- 设计模式-解释器模式
- [设计模式]解释器模式
- 设计模式-解释器模式
- 设计模式-解释器模式
- 设计模式--解释器模式
- 设计模式-解释器模式
- 设计模式-解释器模式
- 【设计模式】解释器模式
- LeetCode-101. Symmetric Tree
- 几种排序算法
- 文本深度表示模型——word2vec&doc2vec词向量模型(转)
- 全字母句
- 36. Valid Sudoku
- Android的设计模式-解释器模式
- vue——带来的冲击
- cassandra column family table
- Kotlin基础(二)
- python-数据处理-merge函数
- HttpServletRequest
- Json
- utils/pkg_list.sh
- 【Linux】nohup重定向例子