PHP設計模式

[TOC]php

依賴注入

策略模式

單例模式

觀察者模式

觀察者模式

咱們來看看報紙和雜誌的訂閱是怎麼回事:數據結構

  • 報社的業務就是出版報紙。
  • 向某家報社訂閱報紙,只要他們有新報紙出版,就會給你送來。
  • 當你不想再看報紙的時候,取消訂閱,他們就不會再送新報紙來。
  • 只要報社還再運營,就會一直有人向他們訂閱報紙或者取消訂閱報紙。

觀察者模式就像訂閱報紙,知識名稱不太同樣:出版社改成「主題」(Subject),訂閱者稱爲「觀察者」(Observer)。實現觀察者模式的方式不僅一種,可是包含Subject和Observer接口的類設計的作法最多見。this

主題能夠註冊、註銷觀察者,當數據改變時,能夠通知觀察者;全部的觀察者必須繼承觀察者接口,這個接口只有一個update()方法,當主題的狀態被改變時調用。主題繼承 SplSubject,這個是PHP內置觀察者模式主題接口;觀察者繼承SplObserver;同時,主題中用SplObjectStorage來存儲觀察者列表。spa

這個是主題:.net

<?php

namespace Observer2;

use SplObserver;

class Subject implements \SplSubject
{

    // 觀察者對象
    private $observers;

    private $upd_data = 10;

    private $upd_msg = '還不應吃飯';

    public function __construct()
    {
        // 數據結構對象容器
        $this->observers = new \SplObjectStorage();
    }

    /**
     *  註冊觀察者
     *
     * Attach an SplObserver
     * @link https://php.net/manual/en/splsubject.attach.php
     * @param SplObserver $observer <p>
     * The <b>SplObserver</b> to attach.
     * </p>
     * @return void
     * @since 5.1.0
     */
    public function attach(SplObserver $observer)
    {
        $this->observers->attach($observer);
    }

    /**
     *  註銷觀察者
     *
     * Detach an observer
     * @link https://php.net/manual/en/splsubject.detach.php
     * @param SplObserver $observer <p>
     * The <b>SplObserver</b> to detach.
     * </p>
     * @return void
     * @since 5.1.0
     */
    public function detach(SplObserver $observer)
    {
        $this->observers->detach($observer);
    }

    /**
     * 通知觀察者
     * Notify an observer
     * @link https://php.net/manual/en/splsubject.notify.php
     * @return void
     * @since 5.1.0
     */
    public function notify()
    {
        // 循環調用觀察者自身的update方法
        if ($this->observers->count() > 0) {
            /** @var \SplObserver $observer */
            foreach ($this->observers as $observer) {
                $observer->update($this);
            }
        }
    }

    /**
     *  數據改變,同時通知觀察者
     *
     * @param $upd_data
     */
    public function updData($upd_data)
    {
        $this->upd_data = $upd_data;

        // 當數據改變時,再須要通知觀察者的地方調用 notify
        $this->notify();
    }

    /**
     *  消息改變,同時通知觀察者
     *
     * @param $upd_msg
     */
    public function updMsg($upd_msg)
    {
        $this->upd_msg = $upd_msg;

        // 這個 notify 也能夠不寫在方法中,靈活運用
        $this->notify();
    }

    /**
     * @return mixed
     */
    public function getUpdData()
    {
        return $this->upd_data;
    }

    /**
     * @return mixed
     */
    public function getUpdMsg()
    {
        return $this->upd_msg;
    }
}

有一個貓貓觀察者:設計

<?php
namespace Observer2;
use SplSubject;

class CatObserver implements \SplObserver
{
    /**
     * 從主題那裏獲得通知
     *
     * Receive update from subject
     * @link https://php.net/manual/en/splobserver.update.php
     * @param SplSubject $subject <p>
     * The <b>SplSubject</b> notifying the observer of an update.
     * </p>
     * @return void
     * @since 5.1.0
     */
    public function update(\SplSubject $subject)
    {
        // 這個 $subject 一開始比較難理解,最後發現確實很聰明
        // 我以爲這種實現方式最好,具體要獲得哪些更新,由註冊觀察者的主題決定
        // 觀察者不知道主題的細節,只知道實現了觀察者接口
        /**
         * @var Subject $subject
         */
        $listen_data = $subject->getUpdData();
        $listen_msg = $subject->getUpdMsg();
        echo 'I am 貓貓觀察者,I get new data:' . $listen_data . ';msg:' . $listen_msg;
        echo '<br>';
    }

}

還有一個狗狗觀察者:code

<?php

namespace Observer2;

class DogObserver implements \SplObserver
{
    
    public function update(\SplSubject $subject)
    {
        /**
         * @var Subject $subject
         */
        $listen_data = $subject->getUpdData();
        $listem_msg = $subject->getUpdMsg();

        echo 'I am 狗狗觀察者,data:' . $listen_data . ';msg:' . $listem_msg;
        echo '<br>';
    }
}

來看一下調用吧:server

<?php
include 'CatObserver.php';
include 'Subject.php';
include 'DogObserver.php';

// 觀察者
$catObserver = new \Observer2\CatObserver();
$dogObserver=new Observer2\DogObserver();

// 主題
$subject = new \Observer2\Subject();

// 註冊觀察者
$subject->attach($catObserver);
$subject->attach($dogObserver);

// 主題有所變化,觀察者獲得對應的變化
$subject->updData(12);
$subject->updMsg('你媽媽喊你回家吃飯');

顯示結果:對象

I am 貓貓觀察者,I get new data:12;msg:還不應吃飯
I am 狗狗觀察者,data:12;msg:還不應吃飯
I am 貓貓觀察者,I get new data:12;msg:你媽媽喊你回家吃飯
I am 狗狗觀察者,data:12;msg:你媽媽喊你回家吃飯

把個人例子弄懂,你也應該能理解觀察者模式了。繼承

來看一下你學到了什麼:
00原則--對象之間鬆耦合設計。

觀察者模式--在對象之間定義一對多的依賴,這樣一來,當一個對象改變狀態,依賴他的對象就會收到通知,並自動更新。

  • 觀察者模式定義了對象之間的一對多關係。
  • 觀察者不知道觀察者的細節,也不知道主題的細節,只知道實現了觀察者接口。
相關文章
相關標籤/搜索