PHP設計模式|觀察者模式(Observer)解析與應用

使用場景

假設項目經理讓咱們寫了一個登錄接口,咔咔擦擦寫完了php

  • 次日讓咱們加入統計登錄次數,而後在後面加代碼laravel

  • 第三天讓咱們判斷登錄地區,又在後面加代碼面試

  • 第四天讓咱們在用戶登錄後推送活動,再再後面加代碼sql

  • 第N天,這個接口已經雜亂到沒人想維護了shell

咱們須要讓項目保持高內聚低耦合,就能夠用到觀察者模式(也不是非要,看需求)數組

概念

觀察者,觀察者,首先要有個被人觀察的角色,這是惟一的,而後會有無數個觀察者去看她,能夠說是一羣人在圍觀一我的,既然有無數個觀衆,那總得有個東西記錄有哪些觀察者,那就應該有一個相似於數組同樣來儲存全部觀察者,總結就是一個被觀察者,無數個觀察者,再有一個容器記錄服務器

個人php高級學習交流社羣「點擊」管理準備好的社羣專屬資料:BAT等一線大廠進階知識體系(相關學習資料以及筆面試題)以及不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨架構

代碼示例

  • 接口示例
// 主題接口
interface Subject{
    public function register(Observer $observer);
    public function notify();
}
// 觀察者接口
interface Observer{
    public function watch();
}

Subject就是被觀察者,Observer就是觀衆,也就是觀察者併發

被觀察者

// 被觀察者
class Action implements Subject{
     public $_observers=array();
     public function register(Observer $observer){
         $this->_observers[]=$observer;
     }
 
     public function notify(){
         foreach ($this->_observers as $observer) {
             $observer->watch();
         }
 
     }
 }

Action實現了被觀察者接口,他如今就是被觀察者,再定義一個$_observers數組,他就是記錄觀衆的容器了。分佈式

首先實現register方法,用它傳入一個觀察者,而後塞到數組裏,再實現notify()方法,它會遍歷容器數組,執行每一個觀察者的watch()方法。

觀察者

// 觀察者
class Cat implements Observer{
     public function watch(){
         echo "Cat watches TV<hr/>";
     }
 }
 class Dog implements Observer{
     public function watch(){
         echo "Dog watches TV<hr/>";
     }
 }
 class People implements Observer{
     public function watch(){
         echo "People watches TV<hr/>";
     }
 }

這裏定義了三個觀察者,全都實現了Observer接口,前面的Subject會循環調用每一個觀察者的watch()方法,因此咱們須要實現每一個觀察者的watch()方法。

調用

// 應用實例
$action=new Action();
$action->register(new Cat());
$action->register(new People());
$action->register(new Dog());
$action->notify();

首先new被觀察者對象,執行它的register()方法,把每一個觀察者都放入容器數組,最後執行notify()方法,通知全部觀察者執行本身的方法。

PHP原生自帶的觀察者模式

PHP有自帶的觀察者模式

  • splsubject接口 - 被觀察者

  • Observer接口 - 觀察者

  • SplObjectStorage對象 - 容器

首先咱們有一個用戶登陸類

class user{

  public function login()
  {
      echo '登陸完畢'
  }

讓他實現splsubject接口成爲被觀察者。

  • 首先在構造函數裏,讓他new SplObjectStorag()對象並賦值到屬性上方便後面調用

  • 實現attach()方法,用來註冊觀察者

  • 實現detach()方法,用來刪除觀察者

  • 實現notify()方法,用來遍歷容器,調用每一個觀察者的update方法(必須是update)

  • rewind方法是容器指針重置到最開始,valid方法檢測容器是否遍歷完成並返回布爾,current方法是獲取當前的觀察者,next方法是將指針後移一位

  • 修改login()方法,在裏面調用notify()來通知觀察者事件完成了

class user implements splsubject{

    protected $observer = null;

    public function __construct()
    {
        $this->observer = new SplObjectStorage();
    }

    public function login()
    {
        $this->notify();
        echo '登陸完畢';
    }

    public function attach(SplObserver $observer)
    {
        $this->observer->attach($observer);
    }

    public function detach(SplObserver $observer)
    {
        $this->observer->detach($observer);
    }

    public function notify()
    {
        $this->observer->rewind();
        while ($this->observer->valid())
        {
            $observer = $this->observer->current();
            $observer->update($this);
            $this->observer->next();
        }
    }
}

觀察者

每一個觀察者實現SplObserver接口,並實現update()方法

class cat implements SplObserver {

    public function update(SplSubject $subject)
    {
        echo '小貓叫一下';
    }
}
class dog implements SplObserver {
    public function update(SplSubject $subject)
    {
        echo '小狗吼一聲';
    }
}

應用

// 實時觀察
$user = new user();
$user->attach(new cat());
$user->attach(new dog());
$user->login();

PHP 互聯網架構師 50K 成長指南+行業問題解決總綱(持續更新)

面試10家公司,收穫9個offer,2020年PHP 面試問題

★若是喜歡個人文章,想與更多資深開發者一塊兒交流學習的話,獲取更多大廠面試相關技術諮詢和指導,歡迎加入咱們的羣-點擊此處

本文由博客羣發一文多發等運營工具平臺 OpenWrite 發佈

相關文章
相關標籤/搜索