PHP設計模式之訪問者模式

PHP設計模式之訪問者模式

訪問者,就像咱們去別人家訪問,或者別人來咱們家看望咱們同樣。咱們每一個人都像是一個實體,而來訪的人都會一一的和咱們打招呼。畢竟,咱們中華民族是很是講究禮數和好客的民族。訪問者是GoF23個設計模式中最複雜的一個模式,也是各種設計模式教材都放在最後的一個模式。先無論難度如何,咱們先看看它的定義和實現。php

Gof類圖及解釋

GoF定義:表示一個做用於某對象結構中的各元素的操做。它使你能夠在不改變各元素的類的前提下定義做用於這些元素的新操做git

GoF類圖github

訪問者模式

代碼實現設計模式

interface Visitor {
    public function VisitConcreteElementA(ConcreteElementA $a);
    function VisitConcreteElementB(ConcreteElementB $b);
}

class ConcreteVisitor1 implements Visitor {
    public function VisitConcreteElementA(ConcreteElementA $a) {
        echo get_class($a) . "被" . get_class($this) . "訪問", PHP_EOL;
    }
    public function VisitConcreteElementB(ConcreteElementB $b) {
        echo get_class($b) . "被" . get_class($this) . "訪問", PHP_EOL;
    }
}

class ConcreteVisitor2 implements Visitor {
    public function VisitConcreteElementA(ConcreteElementA $a) {
        echo get_class($a) . "被" . get_class($this) . "訪問", PHP_EOL;
    }
    public function VisitConcreteElementB(ConcreteElementB $b) {
        echo get_class($b) . "被" . get_class($this) . "訪問", PHP_EOL;
    }
}
複製代碼

抽象的訪問者接口及兩個具體實現。能夠看做是一家小兩口來咱們家做客咯!數據結構

interface Element {
    public function Accept(Visitor $v);
}

class ConcreteElementA implements Element {
    public function Accept(Visitor $v) {
        $v->VisitConcreteElementA($this);
    }
    public function OperationA() {

    }
}

class ConcreteElementB implements Element {
    public function Accept(Visitor $v) {
        $v->VisitConcreteElementB($this);
    }
    public function OperationB() {

    }
}
複製代碼

元素抽象及實現,也能夠看做是要訪問的實體。固然就是我和我媳婦啦。學習

class ObjectStructure {
    private $elements = [];

    public function Attach(Element $element) {
        $this->elements[] = $element;
    }

    public function Detach(Element $element) {
        $position = 0;
        foreach ($this->elements as $e) {
            if ($e == $element) {
                unset($this->elements[$position]);
                break;
            }
            $position++;
        }
    }

    public function Accept(Visitor $visitor) {
        foreach ($this->elements as $e) {
            $e->Accept($visitor);
        }
    }

}
複製代碼

這是一個對象結構,用於保存元素實體並進行訪問調用。你們在客廳裏見面,互相寒暄嘛,這裏就是個客廳this

$o = new ObjectStructure();
$o->Attach(new ConcreteElementA());
$o->Attach(new ConcreteElementB());

$v1 = new ConcreteVisitor1();
$v2 = new ConcreteVisitor2();

$o->Accept($v1);
$o->Accept($v2);
複製代碼

客戶端的調用,總算讓你們正式見面了,互相介紹握手。一次訪問就愉快的完成了。阿里雲

  • 讓訪問者調用指定的元素。這裏須要注意的,訪問者調用元素的行爲通常是固定的,不多會改變的。也就是VisitConcreteElementA()、VisitConcreteElementB()這兩個方法。也就是定義對象結構的類不多改變,但常常須要在此結構上定義新的操做時,會使用訪問者模式
  • 須要對一個對象結構中的對象進行不少不一樣的而且不相關的操做,而你想避免讓這些操做「污染」這些對象的類時,適用於訪問者模式
  • 訪問者模式適合數據結構不變化的狀況。因此,它是一種日常你用不上,但一旦須要的時候就只能用這種模式的模式。GoF:「大多時候你並不須要訪問者模式,但當一旦你須要訪問者模式時,那就是真的須要它了」。由於不多有數據結構不發生變化的狀況
  • 訪問者模式的一些優缺點:易於增長新的操做;集中相關的操做而分離無關的操做;增長新的ConcreteElement類很困難;經過類層次進行訪問;累積狀態;破壞封裝

咱們公司的帳務,只有收入和支出兩項(Element),可是不一樣的部門(Visitor)訪問的時候會給出不一樣的內容。好比我查看的時候只須要查看每個月或每季度的彙總數據便可,財務總監則須要詳細的收支記錄,而會計在作帳時更是須要完整的明細。可見,公司的運營還真的是須要很是普遍的知識的,不只是管理能力,帳務知識也是必要了解的內容!!spa

完整代碼:github.com/zhangyue050…設計

實例

最後一個模式的例子仍是回到咱們的信息發送上來。一樣的仍是多個服務商,它們做爲訪問者須要去使用各自的短信發送及APP推送接口。這時,就可使用訪問者模式來進行操做,實現這些訪問者的所有操做。

訪問者模式信息發送

訪問者模式信息發送

完整源碼:github.com/zhangyue050…

<?php

interface ServiceVisitor {
    public function SendMsg(SendMessage $s);
    function PushMsg(PushMessage $p);
}

class AliYun implements ServiceVisitor {
    public function SendMsg(SendMessage $s) {
        echo '阿里雲發送短信!', PHP_EOL;
    }
    public function PushMsg(PushMessage $p) {
        echo '阿里雲推送信息!', PHP_EOL;
    }
}

class JiGuang implements ServiceVisitor {
    public function SendMsg(SendMessage $s) {
        echo '極光發送短信!', PHP_EOL;
    }
    public function PushMsg(PushMessage $p) {
        echo '極光推送短信!', PHP_EOL;
    }
}

interface Message {
    public function Msg(ServiceVisitor $v);
}

class PushMessage implements Message {
    public function Msg(ServiceVisitor $v) {
        echo '推送腳本啓動:';
        $v->PushMsg($this);
    }
}

class SendMessage implements Message {
    public function Msg(ServiceVisitor $v) {
        echo '短信腳本啓動:';
        $v->SendMsg($this);
    }
}

class ObjectStructure {
    private $elements = [];

    public function Attach(Message $element) {
        $this->elements[] = $element;
    }

    public function Detach(Message $element) {
        $position = 0;
        foreach ($this->elements as $e) {
            if ($e == $element) {
                unset($this->elements[$position]);
                break;
            }
            $position++;
        }
    }

    public function Accept(ServiceVisitor $visitor) {
        foreach ($this->elements as $e) {
            $e->Msg($visitor);
        }
    }

}

$o = new ObjectStructure();
$o->Attach(new PushMessage());
$o->Attach(new SendMessage());

$v1 = new AliYun();
$v2 = new JiGuang();

$o->Accept($v1);
$o->Accept($v2);

複製代碼

說明

  • 咱們假定發送短信和發送推送是不變的兩個行爲,也就是它們倆的數據結構是穩定不變的
  • 這樣咱們就能夠方便的增長ServiceVisitor,當增長百度雲或者別的什麼短信提供商時,就很方便的增長訪問者就能夠了
  • 訪問者模式比較適合數據結構穩定的結構。好比賬單隻有收入支出、人的性別只有男女等

下期看點

至此,設計模式部分咱們已經所有學習完了。其實還少了一個解釋器模式,但這個模式確實是真的的很是少見,有興趣的朋友能夠自行去了解哈。

相關文章
相關標籤/搜索