解释器模式 - Interpreter Pattern
定义
定义一个语言的文法,并且建立一个解释器来解释该语言中的句子。
设计的原则和思想
- 解耦的是需要解释的内容和解释文法的方式。
- 不变部分是解释文法的方式,变化部分是需要解释的内容。
- 核心思想是将语法解析拆分到最小单元,然后按照某种文法规则重新组合。
一句话概括设计模式
用一种类似抽象语法树的表达式去解释一种语言。
终结符和非终结符
终结符
它们是语言的最小组成单位,不能拆分的最小元素。在英文里面终结符是字母。
非终结符
它们都是一个完整的句子,包含一系列终结符或非终结符。在英文里面非终结符是句子或者单词。
结构中包含的角色
- 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 这样的翻译器。