《Android源码设计模式解析与实战》读书笔记(十)

第十章、解释器模式

解释器模式是一种用的比较少的行为型模式,其提供了一种解释语言的语法或表达式的方式。但是它的使用场景确实很广泛,只是因为我们自己很少回去构造一个语言的文法,所以使用较少。

1.定义

给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。(其中语言就是我们需要解释的对象,文法就是这个语言的规律,解释器就是翻译机,通过文法来翻译语言。)

2.使用场景

1.如果某个简单的语言需要解释执行而且可以将该语言中的语句表示为一个抽象的语法树时可以考虑使用解释器模式。

2.在某些特定的领域出现不断重复的问题时,可以将该领域的问题转化为一种语法规则下的语句,然后构建解释器来解释该语句。

3.简单实现

我们使用解释器模式对“m+n+p”这个表达式进行解释,那么代表数字的m、n和p就可以看成终结符号,而“+”这个运算符号可以当做非终结符号。

TerminalExpression:终结符表达式,实现文法中与终结符有关的解释操作。文法中每个终结符都有一个具体的终结表达式与之对应。

NonterminalExpression :非终结符表达式,实现文法中与非终结符有关的解释操作。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

抽象的算数运算解释器

public abstract class ArithemticExpression {
    /**
     * 抽象的解析方法
     * 具体的解析逻辑由具体的子类实现
     *
     * @return 解析得到具体的值
     */
    public abstract int interpreter();
}

数字解释器

public class NumExpression extends ArithemticExpression{

    private int num;

    public NumExpression(int num){
        this.num = num;
    }

    @Override
    public int interpreter() {
        return num;
    }
}

运算符号解释器

public abstract class OperatorExpression extends ArithemticExpression{

    protected ArithemticExpression exp1, exp2;

    public OperatorExpression(ArithemticExpression exp1, ArithemticExpression exp2){
        this.exp1 = exp1;
        this.exp2 = exp2;
    }
}

具体的加法运算符解释器

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 {

    //声明一个Stack栈储存并操作所有相关的解释器
    private Stack<ArithemticExpression> mExpStack = new Stack<ArithemticExpression>();

    public Calculator(String expression){
        //声明两个ArithemticExpression类型的临时变量,储存运算符左右两边的数字解释器
        ArithemticExpression exp1,exp2;

        //根据空格分割表达式字符串(比如1 + 2 + 3 + 4)
        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.parseInt(elements[++i]));
                //通过上面的两个数字解释器构造加法运算解释器
                mExpStack.push(new AdditionExpression(exp1, exp2));
                break;

            default:
                /*
                 * 如果为数字,直接构造数字解释器并压入栈
                 */
                mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
                break;
            }
        }
    }

    /**
     * 计算结果
     *
     * @return 最终的计算结果
     */
    public int calculate(){
        return mExpStack.pop().interpreter();
    }
}

调用

public class Client {
    public static void main(String[] args) {
        Calculator c = new Calculator("22 + 553 + 83 + 5");
        System.out.println("计算结果:"+c.calculate());
    }
}

结果:

计算结果:663

如果相加如减法的操作,在Calculator中加入相应判断即可:

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;

从上面可以看出解释器模式很灵活,他将复杂问题可以简单化、模块化、分离实现、解释执行。

4.Android源码中的模式实现

1.PackageParser

PackageParser是对AndroidManifest.xml配置文件进行读取的,具体原理参考:解析AndroidManifest原理

5.总结

1.优点

最大的优点使其灵活的扩展性,当我们想对文法规则进行扩展延伸时,只需要增加相应的非终结符解释器,并在构建抽象语法树时,使用到新增的解释器对象进行具体的解释即可,非常方便。

2.缺点

1.每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。

2.解释器模式由于使用了大量的循环和递归,效率是个问题,特别是用于解析复杂、冗长的语法时,效率是难以忍受的。

6.参考

参考链接:解释器模式 详解

时间: 2024-10-10 06:16:17

《Android源码设计模式解析与实战》读书笔记(十)的相关文章

《Android源代码设计模式解析与实战》读书笔记(二十二)

第二十二章.享元模式 享元模式是结构型设计模式之中的一个.是对对象池的一种实现.就像它的名字一样,共享对象.避免反复的创建. 我们经常使用的String 就是使用了共享模式.所以String类型的对象创建后就不可改变,假设当两个String对象所包括的内容同样时,JVM仅仅创建一个String对象相应这两个不同的对象引用. 1.定义 採用一个共享来避免大量拥有同样内容对象的开销.使用享元模式可有效支持大量的细粒度对象. 2.使用场景 (1)系统中存在大量的类似对象. (2)细粒度的对象都具备较接

《Android源代码设计模式解析与实战》读书笔记(十)

第十章.解释器模式 解释器模式是一种用的比較少的行为型模式.其提供了一种解释语言的语法或表达式的方式. 可是它的使用场景确实非常广泛,仅仅是由于我们自己非常少回去构造一个语言的文法,所以使用较少. 1.定义 给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子. (当中语言就是我们须要解释的对象,文法就是这个语言的规律,解释器就是翻译机.通过文法来翻译语言.) 2.使用场景 1.假设某个简单的语言须要解释运行并且能够将该语言中的语句表示为一个抽象的语法树时

《Android源代码设计模式解析与实战》读书笔记(十八)

第十八章.代理模式 代理模式也称托付模式,是结构型设计模式之中的一个.是应用广泛的模式之中的一个. 1.定义 为其它对象提供一种代理以控制对这个对象的訪问. 2.使用场景 当无法或不想直接訪问某个对象或訪问某个对象存在困难时能够通过一个代理对象来间接訪问,为了保证client使用的透明性.托付对象与代理对象须要实现相同的接口. 3.UML类图 (1)Subject:抽象主题类.声明真实主题与共同接口方法,该类能够是抽象类或接口. (2)RealSubject:真实主题类(被托付类).尤其运行详细

《Android源代码设计模式解析与实战》读书笔记

1.定义 将对象组合成树形结构以表示"部分-总体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 2.使用场景 (1)表示对象的部分-总体层次结构时. (2)从一个总体中可以独立出部分模块或功能的场景. 3.UML类图 (1)Component:抽象根节点,为组合中的对象声明接口.在适当的情况下.实现全部类共同拥有接口的缺省行为. 声明一个接口用于訪问和管理Component的子节点.可在递归结构中定义一个接口,用于訪问一个父节点,并在合适的情况下实现它. (2)Compo

《Android源代码设计模式解析与实战》读书笔记(八)

第八章.状态模式 1.定义 状态模式中的行为是由状态来决定,不同的状态下有不同的行为.当一个对象的内在状态改变时同意改变其行为,这个对象看起来像是改变了其类. 2.使用场景 1.一个对象的行为取决于它的状态,而且它必须在执行时依据状态改变它的行为. 2.代码中包括大量与对象状态有关的条件语句,比如,一个操作中含有大量的多分支语句.且这些分支依赖于该对象的状态. 3.简单实现 实现效果:首先将电视的状态分为开机与关机状态,开机时能够通过遥控器实现频道切换和调节音量,可是关机时,这些操作都会失效.

《Android源码设计模式解析与实战》读书笔记(十三)

第十三章.备忘录模式 备忘录模式是一种行为模式,该模式用于保存对象当前的状态,并且在之后可以再次恢复到此状态,有点像是我们平常说的"后悔药". 1.定义 在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样,以后就可将该对象恢复到原先保存的状态. 2.使用场景 (1)需要保存一个对象在某一个时刻的状态或部分状态. (2)如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访

Android深度探索(卷1)HAL与驱动开发 第四章 源代码的下载和编译 读书笔记

Android深度探索(卷1)HAL与驱动开发 第四章 源代码的下载和编译 读书笔记     本章学习了使用git下载两套源代码并搭建两个开发环境.分别为Android源代码和Linux内核源代码.Android源代码中包含了HAL(即硬件抽象层) 的代码,并学习了如何搭建这两种开发环境. Android 的移植的本质就是Linux内核的移植,Linux内核的移植主要是Linux驱动的移植.而开发和测试Linux驱动就需要安装以上两个开发环境. 搭建两套环境的具体步骤如下: 一.下载编译和测试A

R实战读书笔记四

第三章 图形入门 本章概要 1 创建和保存图形 2 定义符号.线.颜色和坐标轴 3 文本标注 4 掌控图形维数 5 多幅图合在一起 本章所介绍内容概括如下. 一图胜千字,人们从视觉层更易获取和理解信息. 图形工作 R具有非常强大的绘图功能,看下面代码. > attach(mtcars) > plot(wt, mpg) > abline(lm(mpg~wt)) > title("Regression of MPG on Weight") > detach(m

JavaScript 设计模式与开发实践读书笔记 http://www.open-open.com/lib/view/open1469154727495.html

JavaScript 设计模式与开发实践读书笔记 最近利用碎片时间在 Kindle 上面阅读<JavaScript 设计模式与开发实践读书>这本书,刚开始阅读前两章内容,和大家分享下我觉得可以在项目中用的上的一些笔记. 我的 github 项目会不定时更新,有需要的同学可以移步到我的 github 中去查看源码: https://github.com/lichenbuliren/design-mode-notes 1.currying 函数柯里化 currying 又称 部分求值 .一个 cu

JAVA并发编程实战 读书笔记(二)对象的共享

<java并发编程实战>读书摘要 birdhack 2015年1月2日 对象的共享 JAVA并发编程实战读书笔记 我们已经知道了同步代码块和同步方法可以确保以原子的方式执行操作,但一种常见的误解是,认为关键之synchronized只能用于实现原子性或者确定临界区.同步还有另一个重要的方面:内存可见性. 1.可见性 为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程