天天看點

PHP設計模式—解釋器模式

定義:

解釋器模式(interpreter):給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。解釋器模式需要解決的是,如果一種特定類型的問題發生的頻率足夠高,那麼可能就值得将該問題的各個執行個體表述為一個簡單語言中的句子。這樣就可以建構一個解釋器,該解釋器通過解釋這些句子來解決該問題。

結構:

  • AbstractExpression(抽象表達式):表明一個抽象的解釋操作,這個接口為抽象文法樹中所有的節點所共享。
  • TerminalExpression(終結符表達式):實作與文法中的終結符相關聯的解釋操作,實作抽象表達式中所要求的接口,文法中每一個終結符都有一個具體終結表達式與之相對應。
  • NonterminalExpression(非終結符表達式):為文法中的非終結符實作解釋操作。
  • Context:包含解釋器之外的一些全局資訊。
  • Client:用戶端代碼,建構表示該文法定義的語言中一個特定的句子的抽象文法樹,調用解釋操作。

代碼執行個體:

用解釋器模式設計一個“韶粵通”公共汽車卡的讀卡器程式。

說明:假如“韶粵通”公共汽車讀卡器可以判斷乘客的身份,如果是“韶關”或者“廣州”的“老人” “婦女”“兒童”就可以免費乘車,其他人員乘車一次扣 2 元。

// Expression.php
/**
 * 抽象表達類
 * Class Expression
 */
abstract class Expression
{
    abstract public function interpret($info);
}

// TerminalExpression.php
/**
 * 終結符表達式類
 * Class TerminalExpression
 */
class TerminalExpression extends Expression
{
    private $value = [];

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

    public function interpret($info)
    {
        // TODO: Implement interpret() method.
        if (in_array($info, $this->value)) {
            return true;
        } else {
            return false;
        }
    }
}

// AndExpression.php
/**
 * 非終結符表達式類
 * Class AndExpression
 */
class AndExpression extends Expression
{
    private $city;
    private $person;

    public function __construct(Expression $city, Expression $person)
    {
        $this->city = $city;
        $this->person = $person;
    }

    public function interpret($info)
    {
        // TODO: Implement interpret() method.
        $data = explode('的', $info);
        return $this->city->interpret($data[0]) && $this->person->interpret($data[1]);
    }
}

// Context.php
/**
 * Class Context
 */
class Context
{
    private $city = ["韶關", "廣州"];
    private $person = ["老人", "婦女", "兒童"];
    private $cityPerson;

    public function __construct()
    {
        $cityExpression = new TerminalExpression($this->city);
        $personExpression = new TerminalExpression($this->person);
        $this->cityPerson = new AndExpression($cityExpression, $personExpression);
    }

    public function freeRide($info)
    {
        $isTrue = $this->cityPerson->interpret($info);
        if ($isTrue) {
            echo "您是" . $info . ",您本次乘車免費!\n";
        } else {
            echo $info . ",您不是免費人員,本次乘車扣費2元!\n";
        }
    }
}      

用戶端調用:

$context = new Context();
$context->freeRide("韶關的老人");
$context->freeRide("韶關的年輕人");
$context->freeRide("廣州的婦女");
$context->freeRide("廣州的兒童");
$context->freeRide("山東的兒童");      

結果:

您是韶關的老人,您本次乘車免費!
韶關的年輕人,您不是免費人員,本次乘車扣費2元!
您是廣州的婦女,您本次乘車免費!
您是廣州的兒童,您本次乘車免費!
山東的兒童,您不是免費人員,本次乘車扣費2元!      

總結:

  • 通常當有一個語言需要解釋執行,并且你可将該語言中的句子表示為一個抽象文法樹時,可使用解釋器模式。
  • 使用解釋器模式,意味着可以很容易的改變和擴充文法,因為該模式使用類來表示文法規則,你可以使用繼承來改變或擴充該文法。也比較容易實作文法,因為定義抽象文法樹中各個節點的類的實作大體類似,這些類都易于直接編寫。
  • 解釋器模式也有不足的地方,解釋器模式為文法中的每一條規則至少定義了一個類,是以包含許多規則的文法可能難以管理和維護。