極簡設計模式-直譯器模式

long2ge發表於2021-12-10

定義

定義一個語言的文法,並且建立一個直譯器來解釋該語言中的句子。

設計的原則和思想

  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 這樣的翻譯器。
本作品採用《CC 協議》,轉載必須註明作者和本文連結
Long2Ge

相關文章