解释器模式(Interpreter Pattern)

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。 介绍 意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。 主要解决:对于一些固定文法构建一个解释句子的解释器。 何时使用:如果一种特定类型的问题发生的频率足够高,那么..

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

介绍

意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

主要解决:对于一些固定文法构建一个解释句子的解释器。

何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

如何解决:构件语法树,定义终结符与非终结符。

关键代码:构件环境类,包含解释器之外的一些全局信息,一般是 HashMap。

应用实例:编译器、运算表达式计算。

优点:1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。

缺点:1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。

使用场景:1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 2、一些重复出现的问题可以用一种简单的语言来进行表达。 3、一个简单语法需要解释的场景。

注意事项:可利用场景比较少,JAVA 中如果碰到可以用 expression4J 代替。

 

给定一个语言, 定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

 

 类图:

       

角色:  

       环境角色(PlayContent):定义解释规则的全局信息。

       抽象解释器(Empress):定义了部分解释具体实现,封装了一些由具体解释器实现的接口。

       具体解释器(MusicNote):实现抽象解释器的接口,进行具体的解释执行。

 

代码实现:

复制代码
<?php
header("Content-type:text/html;Charset=utf-8");

//环境角色,定义要解释的全局内容
class Expression{
    public $content;
    function getContent(){
        return $this->content;
    }
}

//抽象解释器
abstract class AbstractInterpreter{
    abstract function interpret($content);
}

//具体解释器,实现抽象解释器的抽象方法
class ChineseInterpreter extends AbstractInterpreter{
    function interpret($content){
        for($i=1;$i<count($content);$i++){
            switch($content[$i]){
            case '0': echo "没有人<br>";break;
            case "1": echo "一个人<br>";break;
            case "2": echo "二个人<br>";break;
            case "3": echo "三个人<br>";break;
            case "4": echo "四个人<br>";break;
            case "5": echo "五个人<br>";break;
            case "6": echo "六个人<br>";break;
            case "7": echo "七个人<br>";break;
            case "8": echo "八个人<br>";break;
            case "9": echo "九个人<br>";break;
            default:echo "其他";
           }
        }
    }
}
class EnglishInterpreter extends AbstractInterpreter{
    function interpret($content){
        for($i=1;$i<count($content);$i++){
             switch($content[$i]){
                case '0': echo "This is nobody<br>";break;
                case "1": echo "This is one people<br>";break;
                case "2": echo "This is two people<br>";break;
                case "3": echo "This is three people<br>";break;
                case "4": echo "This is four people<br>";break;
                case "5": echo "This is five people<br>";break;
                case "6": echo "This is six people<br>";break;
                case "7": echo "This is seven people<br>";break;
                case "8": echo "This is eight people<br>";break;
                case "9": echo "This is nine people<br>";break;
                default:echo "others";
            }
        }
    }
}

//封装好的对具体解释器的调用类,非解释器模式必须的角色
class Interpreter{
     private $interpreter;
     private $content;
     function __construct($expression){
        $this->content = $expression->getContent();
        if($this->content[0] == "Chinese"){
             $this->interpreter = new ChineseInterpreter();
         }else{
              $this->interpreter = new EnglishInterpreter();
         }
     }
     function execute(){
         $this->interpreter->interpret($this->content);
     }
}

//测试
$expression = new Expression();
$expression->content = array("Chinese",3,2,4,4,5);
$interpreter = new Interpreter($expression);
$interpreter->execute();

$expression = new Expression();
$expression->content = array("English",1,2,3,0,0);
$interpreter = new Interpreter($expression);
$interpreter->execute();
//结果:
三个人
二个人
四个人
四个人
五个人
This is one people
This is two people
This is three people
This is nobody
This is nobody
?>

  

       优点:

      解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的非终结符表达式就可以了,若扩展语法,则只要增加非终结符类就可以了。

       缺点:

      1.解释器模式会引起类膨胀

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

      3.解释器模式采用递归调用方法

     每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下使用的,它导致调试非常复杂。想想看,如果要排查一个语法错误,我们是不是要一个一个断点的调试下去,直到最小的语法单元。

 效率问题

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


        适用场景: 

       1、重复发生的问题可以使用解释器模式

        例如,多个应用服务器,每天产生大量的日志,需要对日志文件进行分析处理,由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相同的,但是非终结符表达式就需要制定了。在这种情况下,可以通过程序来一劳永逸地解决该问题。

        2、一个简单语法需要解释的场景

     为什么是简单?文法规则越多,复杂度越高,而且类间还要进行递归调用,不是一般地复杂。想想看,多个类之间的调用你需要什么样的耐心和信心去排查问题。因此,解释器模式一般用来解析比较标准的字符集,例如SQL语法分析,不过该部分逐渐被专用工具所取代。

 

posted @ 2020-03-02 16:24  笨笨韩  阅读(302)  评论(0)    收藏  举报