第十章、解释器模式

解释器模式是一种用的比較少的行为型模式。其提供了一种解释语言的语法或表达式的方式。

可是它的使用场景确实非常广泛,仅仅是由于我们自己非常少回去构造一个语言的文法,所以使用较少。

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.參考

參考链接:解释器模式 详细解释

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

  1. CSS揭秘读书笔记 (一)

    CSS揭秘读书笔记      (一) 一.半透明边框 要想实现半透明边框可以使用border: border: 10px  solid  hsla(0,0%,100%,.5); background: ...

  2. 《CSS世界》笔记二:盒模型四大家族

    上一篇:<CSS世界>笔记一:流/元素/尺寸下一篇:<CSS世界>笔记三:内联元素与对齐 写在前面 在读<CSS世界>第四章之前,粗浅的认为盒模型无非是margin ...

  3. 《精通CSS》读书笔记(一)

    最近新添16本书,目前开始看陈剑瓯翻译的<精通CSS——高级Web标准解决方案>(Andy Budd, CSS Mastery -- Advanced Web Standards Solu ...

  4. 《css世界》笔记之流、元素与基本尺寸

    1. 块级元素 基本特性:就是一个水平流上只能单独显示一个元素,多个块级元素则换行显示. 块级元素和"display 为block 的元素"不是一个概念,display:list- ...

  5. css 揭秘-读书笔记

    css 揭秘 [希]Lea verou 著 css 魔法 译 该书涵盖7大主题,47个css技巧,是css进阶必备书籍,开阔思路,探寻更优雅的解决方案.这本书完全用css渲染出的html写成的(布局. ...

  6. JavaScript权威设计--CSS(简要学习笔记十六)

    1.Document的一些特殊属性 document.lastModified document.URL document.title document.referrer document.domai ...

  7. JavaScript权威设计--JavaScript脚本化文档Document与CSS(简要学习笔记十五)

    1.Document与Element和TEXT是Node的子类. Document:树形的根部节点 Element:HTML元素的节点 TEXT:文本节点   >>HtmlElement与 ...

  8. 《Two Days DIV + CSS》读书笔记——CSS选择器

    1.1.2 CSS选择器 CSS 选择器最基本的有四种:标签选择器.ID 选择器.类选择器.通用选择器. [标签选择器] 一个完整的 HTML 页面由很多不同的标签组成,而标签选择器,则是决定哪些标签 ...

  9. 《Two Days DIV + CSS》读书笔记——CSS控制页面方式

    1.1 你必须知道的知识 (其中包括1.1.1 DIV + CSS的叫法解释:1.1.2 DIV + CSS 名字的误区:以及1.1.3 W3C简介.由于只是背景知识,跳过该章.) 1.2 你必须掌握 ...

  10. CSS Grid 读书笔记

    基本概念 MDN上的解释是这样的 CSS Grid Layout excels at dividing a page into major regions or defining the relati ...

随机推荐

  1. [转]关于Infobright的数据导入

    FROM : http://www.mysqlsky.com/201109/infobright-data-load-error 题记 对于DW系统而言,庞大数据的迁移成本很高:所以导入和导出的速率及 ...

  2. Set a Room Mailbox to Show Details of a Meeting in its Calendar – Office 365

    You may notice that meetings with a ‘Room’ mailbox will by default only show a “Busy” status. Many, ...

  3. jQuery事件命名空间多事件绑定自定义事件js 命名空间 javascript命名空间

    http://blog.csdn.net/pigpigpig4587/article/details/24727791 jQuery事件命名空间 jQuery支持事件命名空间,以方便事件管理.例如,在 ...

  4. asp.net为什么会产生app_offline.htm 这个文件,为什么删除后运行浏览器就不会报应用程序脱机

    一般是发布的时候自动生成的.VS2008在发布程序的时候,会首先在网站目录中生成这个文件,并把该虚拟目录的首页设成这个文件. 这样你在发布程序的时候如果有人访问网站就会看到这个页面. 不影响发布.ap ...

  5. iOS:UICollectionView的扩展应用

    一.介绍 CollectionView是iOS中一个非常重要的控件,它可以实现很多的炫酷的效果,例如轮播图.瀑布流.相册浏览等.其实它和TableView很相似,都是对cell进行复用,提高系统性能. ...

  6. FIR滤波原理及verilog设计

    FIR(Finite Impulse Response)Filter:有限冲激响应滤波器,又称为非递归线性滤波器. FIR滤波器的冲击响应是一个值为滤波器抽头系数的采样序列,其脉冲响应由有限个采样值构 ...

  7. CentOS 6和CentOS 7防火墙的关闭

    CentOS6.5查看防火墙的状态: 1 [linuxidc@localhost ~]$service iptable status 显示结果: 1 2 3 4 5 [linuxidc@localho ...

  8. random_state 参数

    SVC(random_state=0)里有参数 random_state random_state 相当于随机数种子,下面会有代码来解释其作用.图中设置了 random.seed() 就相当于在 SV ...

  9. redis调优 -- 内存碎片

    最近查看了一下redis运行状况,发现公司测试服务器的redis内存不太够用,但是实际占用内存的数据量其实不大,以前也没有这种情况,之前在cache层新增了一个防刷积分任务的逻辑才会这样,搜索一下原因 ...

  10. Android -- ADT变化&aar&Lint

    Switch Case switch case 常用的使用方法: switch(v.getId()){ case R.id.btn1: doClick1(); break; } 在ADT中的改变 在正 ...