解釋器模式

問題:
解釋器模式就是用「迷你語言」來表現程序要解決的問題,以「迷你語言」寫成「迷你程序」來表現具體的問題,例如正則表達式就是一個很好的例子。因此,一般當有一個語言須要解釋執行,而且能夠將該語言中的句子表示爲一個抽象語法樹時,就能夠使用解釋器模式了。php

概念:
給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。正則表達式

實現:
1. 類圖示例:express

2. 代碼示例:(實現一個迷你語言解釋器)this

//表達文本類
class InterpreterContext
{
	private $expressionstore = [];

	public function replace(Expression $exp, $value)
	{
		$this->expressionstore[$exp->getKey()] = $value;
	}

	public function lookup(Expression $exp)
	{
		return $this->expressionstore[$exp->getKey()];
	}
}
//表達式基類
abstract class Expression
{
	private static $keycount = 0;
	private $key;
	abstract public function interpret(InterpreterContext $context);

	public function getKey()
	{
		if(!isset($this->key)) {
			self::$keycount ++;
			$this->key = self::$keycount;
		}
		return $this->key;
	}
}
//字符串表達式類
class LiteralExpression extends Expression
{
	private $value;

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

	public function interpret(InterpreterContext $context)
	{
		$context->replace($this, $this->value);
	}
}
//變量表達式類
class VariableExpression extends Expression
{
	private $name;
	private $val;

	public function __construct($name, $val = null)
	{
		$this->name = $name;
		$this->val = $val;
	}

	public function interpret(InterpreterContext $context)
	{
		if(!is_null($this->val)) {
			$context->replace($this, $this->val);
			$this->val = null;
		}
	}

	public function setValue($value)
	{
		$this->val = $value;
	}

	public function getKey()
	{
		return $this->name;
	}
}
//操做符表達式基類
abstract class OperatorExpression extends Expression
{
	protected $l_op;
	protected $r_op;

	public function __construct(Expression $l_op, Expression $r_op)
	{
		$this->l_op = $l_op;
		$this->r_op = $r_op;
	}

	public function interpret(InterpreterContext $context)
	{
		$this->l_op->interpret($context);
		$this->r_op->interpret($context);
		$result_l = $context->lookup($this->l_op);
		$result_r = $context->lookup($this->r_op);
		$this->doInterpret($context, $result_l, $result_r);
	}

	abstract protected function doInterpret(InterpreterContext $context, $result_l, $result_r);
}
//相等表達式類
class EqualsExpression extends OperatorExpression
{
	protected function doInterpret(InterpreterContext $context, $result_l, $result_r)
	{
		$context->replace($this, $result_l == $result_r);
	}
}
//布爾或表達式類
class BooleanOrExpression extends OperatorExpression
{
	protected function doInterpret(InterpreterContext $context, $result_l, $result_r)
	{
		$context->replace($this, $result_l || $result_r);
	}
}
//布爾與表達式類
class BooleanAndExpression extends OperatorExpression
{
	protected function doInterpret(InterpreterContext $context, $result_l, $result_r)
	{
		$context->replace($this, $result_l && $result_r);
	}
}

//應用:$input equals "4" or $input equals "four"
$context = new InterpreterContext();
$input = new VariableExpression('input');
$statement = new BooleanOrExpression(
	new EqualsExpression($input, new LiteralExpression('four')),
	new EqualsExpression($input, new LiteralExpression('4'))
);
foreach(['four', '4', '52'] as $val) {
	$input->setValue($val);
	echo $val, ':';
	$statement->interpret($context);
	if($context->lookup($statement)) {
		echo 'Yes<br>';
	} else {
		echo 'No<br>';
	}
}

注:示例代碼中同時也使用了模板方法模式和組合模式。spa

效果:
建立了解釋器的核心類後,解釋器很容易進行擴展。可是解釋器模式爲文法中的每一條規則至少定義了一個類,當語言變得複雜,文法包含的規則不少時,須要建立的類的數量會很快增長,所以解釋器模式最好應用於相對小的語言。blog

相關文章
相關標籤/搜索