解释器模式 Interpreter Pattern

未匹配的标注

定义

定义一个语言的文法,并且建立一个解释器来解释该语言中的句子。
解释器模式的应用有查询对象(Query Object),用于表示SQL查询。

设计的原则和思想

  1. 解耦的是需要解释的内容和解释文法的方式。
  2. 不变部分是解释文法的方式,变化部分是需要解释的内容。
  3. 核心思想是将语法解析拆分到最小单元,然后按照某种文法规则重新组合。

一句话概括设计模式

用一种类似抽象语法树的表达式去解释一种语言。

终结符和非终结符

终结符
    它们是语言的最小组成单位,不能拆分的最小元素。在英文里面终结符是字母。

非终结符
    它们都是一个完整的句子,包含一系列终结符或非终结符。在英文里面非终结符是句子或者单词。

结构中包含的角色

  1. AbstractExpression(抽象表达式)
  2. TerminalExpression(终结符表达式)
  3. NonterminalExpression(非终结符表达式)
  4. Context(环境类)

最小可表达代码

// 抽象表达式
abstract class AbstractExpression
{
    public abstract function interpret();
}

// 终结符表达式
class FigureTerminalExpression extends AbstractExpression
{
    private $figure;

    public function __construct($figure)
    {
        $this->figure = $figure;
    }

    public function interpret()
    {
        return $this->figure;
    }
}

// 非终结符表达式
class AddNonterminalExpression extends AbstractExpression
{
    private $left;
    private $right;

    public function __construct(AbstractExpression $left, AbstractExpression $right)
    {
        $this->left = $left;
        $this->right = $right;
    }

    public function interpret()
    {
        return $this->left->interpret() + $this->right->interpret();
    }
}

// 环境类
class Context
{
    private $sentence;

    public function setSentence(String $sentence) 
    {
        $this->sentence = $sentence;
    }

    public function calculate()
    {
        $symbols = [];
        $expressions = [];
        foreach (explode(' ', $this->sentence) as $char) {
            if (is_numeric($char)) {
                $expressions[] = new FigureTerminalExpression($char);
            } else {
                $symbols[] = $char;
            }
        }

        foreach ($symbols as $symbol) {
            if ('+' == $symbol) {
                $left = array_pop($expressions);
                $right = array_pop($expressions);
                $expression = (new AddNonterminalExpression($left, $right));
                array_unshift($expressions, $expression);

                continue;
            }
        }

        return array_pop($expressions)->interpret();
    }
}

$context = new Context();
$sentence = '1 + 1';
$context->setSentence($sentence);
var_dump($context->calculate());

优点

  1. 增加了新的解释表达式的方式。
  2. 易于实现简单文法。每一条文法规则都可以表示为一个类,可以方便地实现一个简单的语言。
  3. 容易实现,改变和扩展文法。
  4. 增加新的解释表达式较为方便。增加一个新的终结符表达式或非终结符表达式类即可。

缺点

  1. 可利用场景比较少。
  2. 对于复杂的文法比较难维护。
  3. 解释器模式会引起类膨胀。
  4. 解释器模式中使用了大量的循环和递归调用,执行效率较低。

何时使用

  1. 一些问题可以用简单的语言来表达,并且不关注执行效率的。
  2. 可以将一个需要解释的语言句子表示为一个抽象语法树。

实际应用场景

  1. sql解析。
  2. 正则表达式。
  3. Google Translate 这样的翻译器。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~