javascript设计模式之解释器模式详解(4)


 void function () {
        var c = new Context();
        // 想要获取d元素的id属性,也就是如下表达式的值:“a/b/c.name”
        // 这个时候c不是终结了,需要把c修改成ElementExpression
        var root = new ElementExpression('root');
        var aEle = new ElementExpression('a');
        var bEle = new ElementExpression('b');
        var cEle = new ElementExpression('c');
        var prop = new PropertyTerminalExpression('name');

// 组合
        root.addEle(aEle);
        aEle.addEle(bEle);
        bEle.addEle(cEle);
        cEle.addEle(prop);

console.log('c的属性name值是 = ' + root.interpret(c));

// 如果要使用同一个上下文,连续进行解析,需要重新初始化上下文对象
        // 比如,要连续的重新再获取一次属性name的值,当然你可以重新组合元素
        // 重新解析,只要是在使用同一个上下文,就需要重新初始化上下文对象
        c.reInit();
        console.log('重新获取c的属性name值是 = ' + root.interpret(c));
    }();


输出: c的属性name值是 = testC 重新获取c的属性name值是 = testC

讲解:

1.解释器模式功能:

解释器模式使用解释器对象来表示和处理相应的语法规则,一般一个解释器处理一条语法规则。理论上来说,只要能用解释器对象把符合语法的表达式表示出来,而且能够构成抽象的语法树,就可以使用解释器模式来处理。

2.语法规则和解释器

语法规则和解释器之间是有对应关系的,一般一个解释器处理一条语法规则,但是反过来并不成立,一条语法规则是可以有多种解释和处理的,也就是一条语法规则可以对应多个解释器。

3.上下文的公用性

上下文在解释器模式中起着非常重要的作用。由于上下文会被传递到所有的解释器中。因此可以在上下文中存储和访问解释器的状态,比如,前面的解释器可以存储一些数据在上下文中,后面的解释器就可以获取这些值。

另外还可以通过上下文传递一些在解释器外部,但是解释器需要的数据,也可以是一些全局的,公共的数据。

上下文还有一个功能,就是可以提供所有解释器对象的公共功能,类似于对象组合,而不是使用继承来获取公共功能,在每个解释器对象中都可以调用

4.谁来构建抽象语法树

在前面的示例中,是自己在客户端手工构建抽象语法树,是很麻烦的,但是在解释器模式中,并没有涉及这部分功能,只是负责对构建好的抽象语法树进行解释处理。后面会介绍可以提供解析器来实现把表达式转换成为抽象语法树。

还有一个问题,就是一条语法规则是可以对应多个解释器对象的,也就是说同一个元素,是可以转换成多个解释器对象的,这也就意味着同样一个表达式,是可以构成不用的抽象语法树的,这也造成构建抽象语法树变得很困难,而且工作量非常大。

5.谁负责解释操作

只要定义好了抽象语法树,肯定是解释器来负责解释执行。虽然有不同的语法规则,但是解释器不负责选择究竟用哪个解释器对象来解释执行语法规则,选择解释器的功能在构建抽象语法树的时候就完成了。

6.解释器模式的调用顺序

1)创建上下文对象

2)创建多个解释器对象,组合抽象语法树

3)调用解释器对象的解释操作

3.1)通过上下文来存储和访问解释器的状态。

对于非终结符解释器对象,递归调用它所包含的子解释器对象。

解释器模式的本质:*分离实现,解释执行*

解释器模使用一个解释器对象处理一个语法规则的方式,把复杂的功能分离开;然后选择需要被执行的功能,并把这些功能组合成为需要被解释执行的抽象语法树;再按照抽象语法树来解释执行,实现相应的功能。

从表面上看,解释器模式关注的是我们平时不太用到的自定义语法的处理;但从实质上看,解释器模式的思想然后是分离,封装,简化,和很多模式是一样的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgpjfd.html