PHP 觀察者(Observer) 設計模式

2021-09-10 22:06:34 字數 4557 閱讀 6342

說到php的設計模式大家往往會想到單例、工廠等設計模式,我們今天來說說我感覺比較好的一種設計模式——觀察者模式。

說到觀察者模式大家可能不太明白,什麼是觀察者模式。所謂觀察者模式,我們可以通俗的理解為你玩在玩爐石傳說的時候,好友在你的對局中觀戰。你的好友就是觀察者,你就是被觀察者。當你勝利或者失敗觀察者都會在視覺上收到通知。哈哈~大家應該懂了吧。

那麼這個觀察者模式有什麼用呢?他可以實現當一些資料發上改變時通知你的觀察者。利用的場景有哪些呢?(我什麼時候能改一下自問自答的習慣…)我們說一下,比如你想實現乙個在站內信提醒功能、建立使用者簡訊提醒功能、資料超出一定數量報警功能等等的一下你覺得可以使用在上面的功能。那麼我們接下來說說觀察者模式的實現方式。

我們利用php自帶spl快速的實現觀察者(observer)設計模式。說道這裡大家問了,何為spl。我們來解釋一下,官方是這樣解釋的:spl是用於解決典型問題(standard problems)的一組介面與類的集合。我在補充一下,他是 php 5 在物件導向上能力提公升的真實寫照,它由一系列內建的類、介面和函式構成。spl 通過加入集合,迭代器,新的異常型別,檔案和資料處理類等提公升了 php 語言的生產力。它還提供了一些十分有用的特性,如本文要介紹的內建 observer 設計模式(所以我們需要在php5.2及以上版本實現)。我們就使用 spl 提供的 splsubject和 splobserver介面以及 splobjectstorage類,快速實現 observer 設計模式。

下面我們介紹一下splsubject 和 splobserver 介面。

observer 設計模式定義了物件間的一種一對多的依賴關係,當被觀察的物件發生改變時,所有依賴於它的物件都會得到通知並被自動更新,而且被觀察的物件和觀察者之間是松耦合的。在該模式中,有目標(subject)和觀察者(observer)兩種角色。目標角色是被觀察的物件,持有並控制著某種狀態,可以被任意多個觀察者作為觀察的目標,spl 中使用 splsubject介面規範了該角色的行為。

splsubject 介面中的方法:

abstract public void attach ( splobserver $observer ) 新增(註冊)乙個觀察者

abstract public void detach ( splobserver $observer ) 刪除乙個觀察者

abstract public void notify ( void ) 當狀態發生改變時,通知所有觀察者

觀察者角色是在目標發生改變時,需要得到通知的物件。spl 中用 splobserver介面規範了該角色的行為:

splobserver 中的方法:

abstract public void update ( splsubject $subject ) 在目標發生改變時接收目標傳送的通知;當關注的目標呼叫其 notify()時被呼叫

該設計模式的核心思想是,splsubject物件會在其狀態改變時呼叫 notify()方法,一旦這個方法被呼叫,任何先前通過 attach()方法註冊上來的 splobserver物件都會以呼叫其 update()方法的方式被更新。

這裡我們不得不說說splobjectstorage 類,這個類的例項很像乙個陣列,但是它所存放的物件都是唯一的。這個特點就為快速實現 observer 設計模式貢獻了不少力量,因為我們不希望同乙個觀察者被註冊多次。該類的另乙個特點是,可以直接從中刪除指定的物件,而不需要遍歷或搜尋整個集合(這就是我們可以快速實現觀察者模式的重點)。

說了這麼多,我們來句乙個例子來實現我們上面說的,這樣也可以更生動形象的體會這個設計模式。接下來我就來實現乙個我們小的時候都經歷過的真是事件,那就是家長監督放假在家的你的各種行為。這個觀察者模式就相當於你家中的攝像頭。嘿嘿(▽

)首先我們被觀察的物件叫小明(為什麼我總出現在例子中…)

class

xiaoming

implements

splsubject

public

function

eat(

$prop

)public

function

play

($prop

)public

function

study

($prop

)public

function

sleep

($prop

)//增加觀察者

public

function

attach

(splobserver $observer

)return

true;}

//刪除觀察者

public

function

detach

(splobserver $observer

)$this

->

observers

->

detach

($observer);

return

true;}

//當狀態改變時,通知觀察者

public

function

notify()

if(count

($this

->do)

>1)

}foreach

($this

->

observers

as$observer)}

public

function

__get

($prop)}

public

function

__set

($prop

,$val

)}

這裡我們建立乙個叫小明的被觀察者,他被觀察的動作有睡覺、吃飯、玩和學習。我們這裡用「拉」的方式獲取小明的實時動態,我們也可以用「推」的方式獲取。如果用「推」的方式獲取那麼我們就不需要__get、__set方法了。我們需要修改notify方法

public

function

notify()

if(count

($this

->do)

>1)

}foreach

($this

->

observers

as$observer

)}

不過下面觀察者也需要改動,稍後再說,我們先按照「拉」的方式繼續寫**。

class

grandpa

implements

splobserver

break

;case1:

if(is_null

($this

->

subjectstate)||

$this

->

subjectstate==1

)$this

->

subjectstate=0

;break

;default

:throw

newexception

('unexpectederrorincarstateobserver::update()');

break;}

}}class

father

implements

splobserver}}

class

mother

implements

splobserver}}

class

sister

implements

splobserver

}}

這裡我們建立了4個觀察者(小明真的是慘),他們分別是爺爺->睡覺、爸爸->玩、媽媽->學習、妹妹->吃。當小明有一下舉動他們會得到通知。那麼我們來執行一下看看效果。

try

catch

(exception$e)

這裡執行的結果是:

爺爺觀察小明起床了

妹妹觀察小明在吃零食

爸爸觀察小明在玩遊戲

媽媽觀察小明在學習

爺爺觀察小明在睡覺

這樣我們觀察者設計模式就快速的實現啦~~~~~不過上面還有乙個我挖的坑,那就是我們如果想用「推」的方式獲取狀態該怎麼實現?我們之前修改了被觀察者,下面我們用觀察者爸爸簡單的說一下,其他觀察者同上。先說一下原理,php 在方法呼叫上有這樣的特性,只要給定的引數(實參)不少於定義時指定的必選引數(沒有預設值的引數),php 就不會報錯。傳入乙個方法的引數個數,可以通過 func_num_args() 函式獲取;多餘的引數可以使用 func_get_arg()函式讀取。注意該函式是從 0 開始計數的,即 0 表示第 1 個實參。利用這個小技巧,update()方法可以通過 func_get_arg(1)接收小明的狀態了。

class

father

implements

splobserver}}

}

本文借鑑:

觀察者模式 Observer

個人理解 觀察者模式的核心是subject的attach和detach方法,載入observer物件 uml類圖 實現 public abstract class subject public void detach observer observer public void notify publ...

觀察者模式 ObServer

觀察者模式 observer 定義物件間的一種一對多的依賴關係,當乙個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新 觀察者模式 observer 觀察者模式定義了一對多依賴關係,讓多個觀察者物件同時監聽某乙個主題物件。讓主題物件在狀態發生變化時,會通知所有觀察者物件,讓他們能夠自動...

觀察者模式(OBSERVER)

觀察者模式是我選擇將其列出來的第乙個模式。看了這個模式的概念之後,有種豁然開朗的感覺。工作也由實踐上公升到了理論。平時使用的各種 net 控制項都使用了這種模式,將這種模式應用到組成乙個系統的各個元件中去,怎乙個 妙 字了得。理解了它之後,不竟又對 net 的框架敬佩有佳。不知道這其中隱藏了多少未知...