摘要:模式定義觀察者模式定義對(duì)象間的一種一對(duì)多依賴關(guān)系,使得每當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴對(duì)象皆得到通知并被自動(dòng)更新。
觀察者模式
Laravel的Event事件系統(tǒng)提供了一個(gè)簡(jiǎn)單的觀察者模式實(shí)現(xiàn),能夠訂閱和監(jiān)聽?wèi)?yīng)用中發(fā)生的各種事件,在PHP的標(biāo)準(zhǔn)庫(kù)(SPL)里甚至提供了三個(gè)接口SplSubject, SplObserver, SplObjectStorage來(lái)讓開發(fā)者更容易地實(shí)現(xiàn)觀察者模式,不過(guò)我還是想脫離SPL提供的接口和特定編程語(yǔ)言來(lái)說(shuō)一下如何通過(guò)面向?qū)ο蟪绦蛟O(shè)計(jì)來(lái)實(shí)現(xiàn)觀察者模式,示例是PHP代碼不過(guò)用其他面向?qū)ο笳Z(yǔ)言實(shí)現(xiàn)起來(lái)也是一樣的。
模式定義觀察者模式(Observer Pattern):定義對(duì)象間的一種一對(duì)多依賴關(guān)系,使得每當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴對(duì)象皆得到通知并被自動(dòng)更新。觀察者模式又叫做發(fā)布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監(jiān)聽器(Source/Listener)模式或從屬者(Dependents)模式。
觀察者模式的核心在于Subject和Observer接口,Subject(主題目標(biāo))包含一個(gè)給定的狀態(tài),觀察者“訂閱”這個(gè)主題,將主題的當(dāng)前狀態(tài)通知觀察者,每次給定狀態(tài)改變時(shí)所有觀察者都會(huì)得到通知。
發(fā)生改變的對(duì)象稱為觀察目標(biāo),而被通知的對(duì)象稱為觀察者,一個(gè)觀察目標(biāo)可以對(duì)應(yīng)多個(gè)觀察者,而且這些觀察者之間沒(méi)有相互聯(lián)系,可以根據(jù)需要增加和刪除觀察者,使得系統(tǒng)更易于擴(kuò)展。
模式結(jié)構(gòu)說(shuō)明Subject 目標(biāo)抽象類
ConcreteSubject 具體目標(biāo)
Observer 觀察者抽象類
ConcreteObserver 具體觀察者
應(yīng)用舉例比如在設(shè)置用戶(主題)的狀態(tài)后要分別發(fā)送當(dāng)前的狀態(tài)描述信息給用戶的郵箱和手機(jī),我們可以使用兩個(gè)觀察者訂閱用戶的狀態(tài),一旦設(shè)置狀態(tài)后主題就會(huì)通知的訂閱了狀態(tài)改變的觀察者,在兩個(gè)觀察者里面我們可以分別來(lái)實(shí)現(xiàn)發(fā)送郵件信息和短信信息的功能。
抽象目標(biāo)類
abstract class Subject { protected $stateNow; protected $observers = []; public function attach(Observer $observer) { array_push($this->observers, $observer); } public function detach(Observer $ob) { $pos = 0; foreach ($this->observers as $viewer) { if ($viewer == $ob) { array_splice($this->observers, $pos, 1); } $pos++; } } public function notify() { foreach ($this->observers as $viewer) { $viewer->update($this); } } }
在抽象類中attach detach 和notify都是具體方法,這些是繼承才能使用的方法,將由Subject的子類使用。
具體目標(biāo)類
class ConcreteSubject extends Subject { public function setState($state) { $this->stateNow = $state; $this->notify(); } public function getState() { return $this->stateNow; } }
抽象觀察者
abstract class Observer { abstract public function update(Subject $subject); }
在抽象觀察者中,抽象方法update等待子類為它提供一個(gè)特定的實(shí)現(xiàn)。
具體觀察者
class ConcreteObserverDT extends Observer { private $currentState; public function update(Subject $subject) { $this->currentState = $subject->getState(); echo "". $this->currentState .""; } } class ConcreteObserverPhone extends Observer { private $currentState; public function update(Subject $subject) { $this->currentState = $subject->getState(); echo "". $this->currentState .""; } }
在例子中為了理解起來(lái)簡(jiǎn)單,我們只是根據(jù)不同的客戶端設(shè)置了不同的內(nèi)容樣式,實(shí)際應(yīng)用中可以真正的調(diào)用郵件和短信服務(wù)來(lái)發(fā)送信息。
使用觀察者模式
class Client { public function __construct() { $sub = new ConcreteSubject(); $obDT = new ConcreteObserverDT(); $obPhone = new ConcreteObserverPhone(); $sub->attach($obDT); $sub->attach($obPhone); $sub->setState("Hello World"); } } $worker = new Client();何時(shí)使用觀察者模式
一個(gè)對(duì)象的改變將導(dǎo)致其他一個(gè)或多個(gè)對(duì)象也發(fā)生改變,而不知道具體有多少對(duì)象將發(fā)生改變,可以降低對(duì)象之間的耦合度。
一個(gè)對(duì)象必須通知其他對(duì)象,而并不知道這些對(duì)象是誰(shuí)。
基于事件觸發(fā)機(jī)制來(lái)解耦復(fù)雜邏輯時(shí),從整個(gè)邏輯的不同關(guān)鍵點(diǎn)抽象出不同的事件,主流程只需要關(guān)心最核心的邏輯并能正確地觸發(fā)事件(Subject),其余相關(guān)功能實(shí)現(xiàn)由觀察者或者叫訂閱者來(lái)完成。
總結(jié)觀察者模式定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)目標(biāo)對(duì)象,當(dāng)這個(gè)目標(biāo)對(duì)象的狀態(tài)發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,使它們能夠自動(dòng)更新。
模式包含四個(gè)角色:目標(biāo)又稱為主題,它是指被觀察的對(duì)象;具體目標(biāo)是目標(biāo)類的子類,通常它包含有經(jīng)常發(fā)生改變的數(shù)據(jù),當(dāng)它的狀態(tài)發(fā)生改變時(shí),向它的各個(gè)觀察者發(fā)出通知;觀察者將對(duì)觀察目標(biāo)的改變做出反應(yīng);在具體觀察者中維護(hù)一個(gè)指向具體目標(biāo)對(duì)象的引用,它存儲(chǔ)具體觀察者的有關(guān)狀態(tài),這些狀態(tài)需要和具體目標(biāo)的狀態(tài)保持一致。
觀察者模式的主要優(yōu)點(diǎn)在于可以實(shí)現(xiàn)表示層和數(shù)據(jù)邏輯層的分離,并在觀察目標(biāo)和觀察者之間建立一個(gè)抽象的耦合,支持廣播通信;其主要缺點(diǎn)在于如果一個(gè)觀察目標(biāo)對(duì)象有很多直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間,而且如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰。
本文已經(jīng)收錄在系列文章Laravel源碼學(xué)習(xí)里,歡迎訪問(wèn)閱讀。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/28804.html
摘要:對(duì)于包含通配符的事件名,會(huì)被統(tǒng)一放入數(shù)組中,是用來(lái)創(chuàng)建事件對(duì)應(yīng)的的如果是監(jiān)聽器是類,去創(chuàng)建監(jiān)聽類創(chuàng)建的時(shí)候,會(huì)判斷監(jiān)聽對(duì)象是監(jiān)聽類還是閉包函數(shù)。對(duì)于閉包監(jiān)聽來(lái)說(shuō),會(huì)再包裝一層返回一個(gè)閉包函數(shù)作為事件的監(jiān)聽者。 事件系統(tǒng) Laravel 的事件提供了一個(gè)簡(jiǎn)單的觀察者實(shí)現(xiàn),能夠訂閱和監(jiān)聽?wèi)?yīng)用中發(fā)生的各種事件。事件機(jī)制是一種很好的應(yīng)用解耦方式,因?yàn)橐粋€(gè)事件可以擁有多個(gè)互不依賴的監(jiān)聽器。lar...
摘要:外觀模式的目的在于降低系統(tǒng)的復(fù)雜程度。在不引入抽象外觀類的情況下,增加新的子系統(tǒng)可能需要修改外觀類或客戶端的源代碼,違背了開閉原則。 外觀模式 外觀模式(Facade Pattern):外部與一個(gè)子系統(tǒng)的通信必須通過(guò)一個(gè)統(tǒng)一的外觀對(duì)象進(jìn)行,為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,外觀模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。外觀模式又稱為門面模式,它是一種對(duì)象結(jié)構(gòu)型模...
摘要:解析出后將進(jìn)入應(yīng)用的請(qǐng)求對(duì)象傳遞給的方法,在方法負(fù)責(zé)處理流入應(yīng)用的請(qǐng)求對(duì)象并返回響應(yīng)對(duì)象。攜帶了本次迭代的值。通過(guò)這種方式讓請(qǐng)求對(duì)象依次流過(guò)了要通過(guò)的中間件,達(dá)到目的地的方法。 中間件(Middleware)在Laravel中起著過(guò)濾進(jìn)入應(yīng)用的HTTP請(qǐng)求對(duì)象(Request)和完善離開應(yīng)用的HTTP響應(yīng)對(duì)象(Reponse)的作用, 而且可以通過(guò)應(yīng)用多個(gè)中間件來(lái)層層過(guò)濾請(qǐng)求、逐步完善...
摘要:系統(tǒng)的核心是由的認(rèn)證組件的看守器和提供器組成。使用的認(rèn)證系統(tǒng),幾乎所有東西都已經(jīng)為你配置好了。其配置文件位于,其中包含了用于調(diào)整認(rèn)證服務(wù)行為的注釋清晰的選項(xiàng)配置。 用戶認(rèn)證系統(tǒng)(基礎(chǔ)介紹) 使用過(guò)Laravel的開發(fā)者都知道,Laravel自帶了一個(gè)認(rèn)證系統(tǒng)來(lái)提供基本的用戶注冊(cè)、登錄、認(rèn)證、找回密碼,如果Auth系統(tǒng)里提供的基礎(chǔ)功能不滿足需求還可以很方便的在這些基礎(chǔ)功能上進(jìn)行擴(kuò)展。這篇...
摘要:過(guò)去一年時(shí)間寫了多篇文章來(lái)探討了我認(rèn)為的框架最核心部分的設(shè)計(jì)思路代碼實(shí)現(xiàn)。為了大家閱讀方便,我把這些源碼學(xué)習(xí)的文章匯總到這里。數(shù)據(jù)庫(kù)算法和數(shù)據(jù)結(jié)構(gòu)這些都是編程的內(nèi)功,只有內(nèi)功深厚了才能解決遇到的復(fù)雜問(wèn)題。 過(guò)去一年時(shí)間寫了20多篇文章來(lái)探討了我認(rèn)為的Larave框架最核心部分的設(shè)計(jì)思路、代碼實(shí)現(xiàn)。通過(guò)更新文章自己在軟件設(shè)計(jì)、文字表達(dá)方面都有所提高,在剛開始決定寫Laravel源碼分析地...
閱讀 3716·2021-11-11 16:55
閱讀 1658·2021-10-08 10:04
閱讀 3593·2021-09-27 13:36
閱讀 2796·2019-08-30 15:53
閱讀 1874·2019-08-30 11:17
閱讀 1276·2019-08-29 16:55
閱讀 2115·2019-08-29 13:57
閱讀 2531·2019-08-29 13:13