PHP設計模式——觀察者模式

前言

知識就是做爲觀察者所得到的結論,通過科學培訓的觀察者會爲咱們提供全部能感知的現實。設計觀察者模式是爲了讓一個對象跟蹤某個狀態,知道狀態什麼時候改變,一旦狀態改變,全部訂閱對象都能獲得通知。若是須要保證一個狀態的一致性(好比說:狀態觸發類的應用),可是這個給定狀態可能有多個不一樣的用戶等級,這種狀況下觀察者模式就很適用,並且頗有幫助,各司其職。利用觀察者模式能夠維護一致性,同時記錄建立一個給定的狀態的對象個數。php

觀察者模式很直觀。何須讓多個對象建立或跟蹤一個給定的狀態呢?若是由一個對象完成這個工做,而後通知其餘可能用到這個狀態的對象,這樣會合理得多。html

使用SPL實現觀察者模式

一、可用於觀察者設計模式的3個SPL接口/類以下:
● SplSubject
● SplObserver
● SplObjectStoragesql

1.一、SplSubjectthinkphp

<?php

namespace common\observer;

use Yii;

/**
 * SplSubject.
 *
 */
interface SplSubject
{
    /*SplSubject 接口*/
    public function attach (SplObserver $observer);
    public function detach (SplObserver $observer);
    public function notify ();
}

注意這個SplSubject 接口指定attach()和detach()方法參數中$observer的數據類型必須是一個SplObserver 對象。設計模式

1.二、SplObserver數據結構

SplObserver 接口只有一個update()方法,以下所示:函數

<?php

namespace common\observer;

use Yii;

/**
 * SplObserver
 *
 */
interface SplObserver
{
    /*更新方法*/
    public function update (SplSubject $subject);
}

update()方法對於觀察者模式相當重要,由於它會獲得Subject狀態的最新變化,並交給觀察者實例。this

1.三、SplObjectStoragespa

SplObjectStorage 類與觀察者設計模式沒有內在的關係,不過經過它其內置的attach()和detach()方法能夠很方便的將觀察者實例與一個主題實例相關聯以及解除關聯。.net

<?php

namespace common\observer;

use Yii;

/**
 * SplObjectStorage 存儲對象的類
 * 
 * @property string $storage 存儲對象
 * 
 */
class SplObjectStorage
{    
    public $storage;

    //增長方法
    
    public function attach(SplObserver $observer)
    { 
        $this->storage[] = $observer;
    }

    //刪除方法

    public function detach(SplObserver $observer)
    {  
        if(is_int($idx = array_search($observer, $this->storage)))
        {
            unset($this->storage[$idx]);
        }
    }
}

註釋:若是直接用PHP類庫的SplObjectStorage類的話,1.3能夠不看了,只須要把1.4裏面的$this->observers = new SplObjectStorage();修改成$this->observers = new \SplObjectStorage();(緣由能夠去了下PHP的解命名空間和文件加載機制。參考資料),notify方法裏的$this->observers->storage修改成$this->observers便可。

1.四、SPL具體主題

SplSubject接口不包括獲取方法和設置方法,不過這也是觀察者設計模式中的一部分,因此須要增長獲取方法和設置方法。設置方法setData()包含一個參數,這是要增長的任何類型的數據。獲取方法getData()存儲當前的主題狀態,由具體觀察者用來更新觀察者數據。
另外還增長了setObservers()方法。並非在構造函數中設置SplObjectStorage()實例,也沒有在setData()方法中設置觀察者實例,這裏實現了一個單獨的setObservers()方法,能夠提供更輕鬆的耦合,並容許有多組觀察者。

<?php

namespace common\observer;

use Yii;
 
//ConcreteSubject
 
class ConcreteSubject implements SplSubject
{
 
    private $observers,$data;
 
    public function setObservers()
    {
 
        //sqlObjectStorage 專門用來存儲對象的類
 
        $this->observers = new SplObjectStorage();


    }

    //添加觀察者
 
    public function attach(SplObserver $observer)
    {
 
        $this->observers->attach($observer);
 
    }
 
    //剔除觀察者
 
    public function detach(SplObserver $observer)
    {
 
        $this->observers->detach($observer);
 
    }
 
    //通知notify

    public function notify()
    {  
        foreach ($this->observers->storage as $key =>$observer) { 
            $observer->update($this);
        }
 
    }

    //設置方法

    public function setData($dataNow)
    { 
        $this->data=$dataNow;
    }

    //獲取方法

    public function getData()
    {   
        return $this->data;
    }
 
}
 
?>

1.五、SPL具體觀察者

用於實現更新函數來更新關聯的觀察者實例。

<?php


namespace common\observer;

use Yii;
 
//ConcreteObserver
 
class ConcreteObserver implements SplObserver
{
 
    public function update(SplSubject $subject)
    {  
        echo $subject->getData()."</br>";
    }
 
}
 
?>

(附加的普通用戶具體觀察者)

<?php


namespace common\observer;

use Yii;
 
//Userbservers
 
class UserObserver implements SplObserver
{
 
    public function update(SplSubject $subject)
    {
 
        echo '我是普通用戶,請給我對應的普通用戶服務';
 
    }
 
}
?>

1.六、SPL客戶

「SPL」Client 類只是一個標準客戶。這個客戶按照SPL接口向具體主題和觀察者發出多個請求,不過本身並無實現SPL類和接口。

<?php


namespace common\observer;

use Yii;
 
//Client

class Client
{
 
    public function __construct()
    {
        echo "<h3> 創造新的具體觀察者,新的具體主體:</h3>";

        $ob1 = new ConcreteObserver();
        $ob2 = new ConcreteObserver();
        $ob3 = new ConcreteObserver();

        $Subject = new ConcreteSubject();
        $Subject->setObservers();
        $Subject->setData("這是你的數據!");
        $Subject->attach($ob1);
        $Subject->attach($ob2);
        $Subject->attach($ob3);

        $Subject->notify();

        echo "<h3>刪除ob3,結果是ob1和ob2的通知:</h3>";
        $Subject->detach($ob3);
        $Subject->notify();

        echo "<h3>剩餘的數據和附加數據還有刪除ob2,結果是ob1和ob3的通知:</h3>";
        $Subject->setData("更多的數據,只有ob1和ob3是須要的");
        $Subject->attach($ob3);
        $Subject->detach($ob2);
        $Subject->notify();
  
        echo "<h3>剩餘數據和附加新數據,結果是ob1和ob3還有「新數據」的通知:</h3>";
        $Subject->attach(new \common\observer\UserObserver);
        $Subject->notify();
    }
 
}
 
?>

1.七、Client的調用輸出以下:

調用:$worker=new commonobserverClient();

輸出:
圖片描述

總結分析

這裏SplObjectStorage類是我本身寫的,貼出來分享一下。PHP5.1.0以及更高的版本有不少特性,其中之一就是提供了一組能夠用於觀察者的設計模式的接口。能夠研究一下怎麼使用,SplObserver接口以及SplSubject和SplObjectStorage接口,利用這些接口,構建觀察者模式簡直易如反掌。「SPL」是標準PHP類庫(Standard PHP Library)的簡寫,這個庫中包括一組解決標準問題的接口和類。參考手冊

相關資料

關於觀察者模式
利用 SPL 快速實現 Observer 設計模式
PHP SPL標準庫之數據結構對象容器(SplObjectStorage)

相關文章
相關標籤/搜索