极简设计模式-解释器模式

PHP技术
375
0
0
2022-08-04

解释器模式 - Interpreter Pattern

定义

定义一个语言的文法,并且建立一个解释器来解释该语言中的句子。

设计的原则和思想

  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 这样的翻译器。