深入淺析PHP中的訪客模式

青灯夜游
發布: 2023-04-10 13:54:02
轉載
2045 人瀏覽過

在之前的文章《PHP中什麼是狀態模式?透過實例來了解它》中我們介紹了PHP中的狀態模式,以下這篇文章帶大家了解PHP設計模式中的訪客模式。

深入淺析PHP中的訪客模式

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

Gof類別圖及解釋

GoF定義:表示一個作用於某物件結構中的各元素的操作。它使你可以在不改變各元素的類別的前提下定義作用於這些元素的新操作

#GoF類別圖

深入淺析PHP中的訪客模式

程式碼實作

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);
        }
    }

}
登入後複製

這是一個物件結構,用於保存元素實體並進行存取呼叫。大家在客廳見面,互相寒暄嘛,這裡就是個客廳

$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)存取的時候會給出不同的內容。例如我查看的時候只需要查看每月或每季的總數據即可,財務總監則需要詳細的收支記錄,而會計在做帳時更是需要完整的明細。可見,公司的營運真的是需要非常廣泛的知識的,不僅是管理能力,帳務知識也是必要了解的內容! !

完整程式碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/23.visitor/source/visitor.php

#實例

最後一個模式的範例還是回到我們的訊息傳送上。同樣的還是多個服務商,它們作為訪客需要去使用各自的簡訊發送及APP推送介面。這時,就可以使用訪客模式來進行操作,實現這些訪客的全部操作。

訪客模式資訊發送

深入淺析PHP中的訪客模式

#完整原始碼:https://github.com/zhangyue0503/designpatterns- php/blob/master/23.visitor/source/visitor-msg.php

<?php

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

class AliYun implements ServiceVisitor
{
    public function SendMsg(SendMessage $s)
    {
        echo &#39;阿里云发送短信!&#39;, PHP_EOL;
    }
    public function PushMsg(PushMessage $p)
    {
        echo &#39;阿里云推送信息!&#39;, PHP_EOL;
    }
}

class JiGuang implements ServiceVisitor
{
    public function SendMsg(SendMessage $s)
    {
        echo &#39;极光发送短信!&#39;, PHP_EOL;
    }
    public function PushMsg(PushMessage $p)
    {
        echo &#39;极光推送短信!&#39;, PHP_EOL;
    }
}

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

class PushMessage implements Message
{
    public function Msg(ServiceVisitor $v)
    {
        echo &#39;推送脚本启动:&#39;;
        $v->PushMsg($this);
    }
}

class SendMessage implements Message
{
    public function Msg(ServiceVisitor $v)
    {
        echo &#39;短信脚本启动:&#39;;
        $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,當增加百度雲或別的什麼簡訊提供者時,就很方便的增加訪客就可以了
  • 訪客模式比較適合資料結構穩定的結構。例如帳單只有收入支出、人的性別只有男女等

原文地址:https://juejin.cn/post/6844903993240453133

作者:硬核心項目經理

推薦學習:《PHP影片教學

以上是深入淺析PHP中的訪客模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!