定義
定義一個語言的文法,並且建立一個直譯器來解釋該語言中的句子。
設計的原則和思想
- 解耦的是需要解釋的內容和解釋文法的方式。
- 不變部分是解釋文法的方式,變化部分是需要解釋的內容。
- 核心思想是將語法解析拆分到最小單元,然後按照某種文法規則重新組合。
一句話概括設計模式
用一種類似抽象語法樹的表示式去解釋一種語言。
終結符和非終結符
終結符
它們是語言的最小組成單位,不能拆分的最小元素。在英文裡面終結符是字母。
非終結符
它們都是一個完整的句子,包含一系列終結符或非終結符。在英文裡面非終結符是句子或者單詞。
結構中包含的角色
- AbstractExpression(抽象表示式)
- TerminalExpression(終結符表示式)
- NonterminalExpression(非終結符表示式)
- 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());
優點
- 增加了新的解釋表示式的方式。
- 易於實現簡單文法。每一條文法規則都可以表示為一個類,可以方便地實現一個簡單的語言。
- 容易實現,改變和擴充套件文法。
- 增加新的解釋表示式較為方便。增加一個新的終結符表示式或非終結符表示式類即可。
缺點
- 可利用場景比較少。
- 對於複雜的文法比較難維護。
- 直譯器模式會引起類膨脹。
- 直譯器模式中使用了大量的迴圈和遞迴呼叫,執行效率較低。
何時使用
- 一些問題可以用簡單的語言來表達,並且不關注執行效率的。
- 可以將一個需要解釋的語言句子表示為一個抽象語法樹。
實際應用場景
- sql解析。
- 正規表示式。
- Google Translate 這樣的翻譯器。
本作品採用《CC 協議》,轉載必須註明作者和本文連結