PHP設計模式-觀察者模式

觀察者模式(又稱爲發佈-訂閱(Publish/Subscribe)模式,屬於行爲型模式的一種,它是將行爲獨立模塊化,下降了行爲和主體的耦合性。它定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態變化時,會通知全部的觀察者對象,使他們可以自動更新本身。php

  • Subject:抽象主題(抽象被觀察者),抽象主題角色把全部觀察者對象保存在一個集合裏,每一個主題均可以有任意數量的觀察者,抽象主題提供一個接口,能夠增長和刪除觀察者對象。模塊化

  • ConcreteSubject:具體主題(具體被觀察者),該角色將有關狀態存入具體觀察者對象,在具體主題的內部狀態發生改變時,給全部註冊過的觀察者發送通知。this

  • Observer:抽象觀察者,是觀察者者的抽象類,它定義了一個更新接口,使得在獲得主題更改通知時更新本身。code

  • ConcrereObserver:具體觀察者,是實現抽象觀察者定義的更新接口,以便在獲得主題更改通知時更新自身的狀態。server

PHP 內置了對象

  • SplSubject 抽象主題 Interface接口

  • SplObserver 抽象觀察者 Interface事件

接口約束ip

// 主題 被觀察者
interface SplSubject {
    public function attach(SplObserver $observer); //註冊觀察者到當前主題
    public function detach(SplObserver $observer); //從當前主題刪除觀察者
    public function notify(); //主題狀態更新時通知全部的觀察者作相應的處理
}

// 觀察者
interface SplObserver {
    public function update(SplSubject $subject); //註冊觀察者到當前主題
}

經過項目中的實際應用能更容易的去理解觀察者模式開發

下面咱們以用戶爲主題,郵件模塊和短信模塊爲觀察者

當用戶註冊成功時,郵件觀察者或短信觀察者則收到相應的通知,發送郵件和短信給用戶

User 主題

<?php
/**
 * 主題類(被觀察者至關於一個主題,觀察者訂閱這個主題)
 * 當咱們註冊用戶成功的時候想發送 email 和 sms 通知用戶註冊成功
 * 則 能夠將 SendEmail 和 SendSms 做爲觀察者
 * 註冊到 User 的觀察者中
 * 當 User register 成功時 notify 給 observers
 * 各 observe 經過約定的 update 接口進行相應的處理 發郵件或發短信
 */
class User implements SplSubject
{
    public $name;
    public $email;
    public $mobile;

    /**
     * 當前主題下的觀察者集合
     * @var array
     */
    private $observers = [];

    /**
     * 模擬註冊
     * @param  [type] $name   [description]
     * @param  [type] $email  [description]
     * @param  [type] $mobile [description]
     * @return [type]         [description]
     */
    public function register($name, $email, $mobile)
    {
        $this->name   = $name;
        $this->email  = $email;
        $this->mobile = $mobile;

        //business handle and register success
        $reg_result = true;
        if ($reg_result) {
            $this->notify(); // 註冊成功 全部的觀察者將會收到此主題的通知
            return true;
        }

        return false;
    }

    /**
     * 當前主題註冊新的觀察者
     * @param  SplObserver $observer [description]
     * @return [type]                [description]
     */
    public function attach(SplObserver $observer)
    {
        return array_push($this->observers, $observer);
    }

    /**
     * 當前主題刪除已註冊的觀察者
     * @param  SplObserver $observer [description]
     * @return [type]                [description]
     */
    public function detach(SplObserver $observer)
    {
        $key = array_search($observer, $this->observers, true);

        if (false !== $key) {
            unset($this->observers[$key]);
            return true;
        }

        return false;
    }

    /**
     * 狀態更新 通知全部的觀察者
     * @return [type] [description]
     */
    public function notify()
    {
        if (! empty($this->observers)) {
            foreach ($this->observers as $key => $observer) {
                $observer->update($this);
            }
        }

        return true;
    }

}

Email/Sms 觀察者

/**
 * 觀察者經過 update 來接受主題的更新通知
 */
class EmailObserver implements SplObserver
{
    /**
     * 觀察者接收主題通知的接口
     * @param  SplSubject $user [description]
     * @return [type]           [description]
     */
    public function update(SplSubject $user)
    {
        echo "send email to " . $user->email . PHP_EOL;
    }
}

class SmsObserver implements SplObserver
{
    public function update(SplSubject $user)
    {
        echo "send sms to " . $user->mobile . PHP_EOL;
    }
}

業務

// User 主題
$user = new User();

// 爲 user 註冊 Email 觀察者 (Email 觀察者訂閱 User 主題)
$emailObserver = new EmailObserver();
$user->attach($emailObserver);

// 爲 user 註冊 Sms 觀察者 (Sms 觀察者訂閱 User 主題)
$smsObserver = new SmsObserver();
$user->attach($smsObserver);

// 從 user 上刪除 Sms 觀察者 (Sms 觀察者取消訂閱 User 主題)
//$user->detach($smsObserver);

// register 中會根據註冊結果通知觀察者 觀察者作相應的處理
$user->register("big cat", "32448732@qq.com", "1888888888");

結果

send email to 32448732@qq.com
send sms to 1888888888
[Finished in 0.1s]

其實觀察者模式相似於事件註冊和鉤子回調,平常開發中咱們可能重構分離出一部分類的行爲到外部,封裝成獨立的功能模塊,在註冊到類中,能夠使用事件註冊,也能夠使用觀察者模式

相關文章
相關標籤/搜索