摘要:模式定義觀察者模式定義對象間的一種一對多依賴關系,使得每當一個對象狀態發生改變時,其相關依賴對象皆得到通知并被自動更新。
觀察者模式
Laravel的Event事件系統提供了一個簡單的觀察者模式實現,能夠訂閱和監聽應用中發生的各種事件,在PHP的標準庫(SPL)里甚至提供了三個接口SplSubject, SplObserver, SplObjectStorage來讓開發者更容易地實現觀察者模式,不過我還是想脫離SPL提供的接口和特定編程語言來說一下如何通過面向對象程序設計來實現觀察者模式,示例是PHP代碼不過用其他面向對象語言實現起來也是一樣的。
模式定義觀察者模式(Observer Pattern):定義對象間的一種一對多依賴關系,使得每當一個對象狀態發生改變時,其相關依賴對象皆得到通知并被自動更新。觀察者模式又叫做發布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
觀察者模式的核心在于Subject和Observer接口,Subject(主題目標)包含一個給定的狀態,觀察者“訂閱”這個主題,將主題的當前狀態通知觀察者,每次給定狀態改變時所有觀察者都會得到通知。
發生改變的對象稱為觀察目標,而被通知的對象稱為觀察者,一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯系,可以根據需要增加和刪除觀察者,使得系統更易于擴展。
模式結構說明Subject 目標抽象類
ConcreteSubject 具體目標
Observer 觀察者抽象類
ConcreteObserver 具體觀察者
應用舉例比如在設置用戶(主題)的狀態后要分別發送當前的狀態描述信息給用戶的郵箱和手機,我們可以使用兩個觀察者訂閱用戶的狀態,一旦設置狀態后主題就會通知的訂閱了狀態改變的觀察者,在兩個觀察者里面我們可以分別來實現發送郵件信息和短信信息的功能。
抽象目標類
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的子類使用。
具體目標類
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等待子類為它提供一個特定的實現。
具體觀察者
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 .""; } }
在例子中為了理解起來簡單,我們只是根據不同的客戶端設置了不同的內容樣式,實際應用中可以真正的調用郵件和短信服務來發送信息。
使用觀察者模式
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();何時使用觀察者模式
一個對象的改變將導致其他一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,可以降低對象之間的耦合度。
一個對象必須通知其他對象,而并不知道這些對象是誰。
基于事件觸發機制來解耦復雜邏輯時,從整個邏輯的不同關鍵點抽象出不同的事件,主流程只需要關心最核心的邏輯并能正確地觸發事件(Subject),其余相關功能實現由觀察者或者叫訂閱者來完成。
總結觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個目標對象,當這個目標對象的狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新。
模式包含四個角色:目標又稱為主題,它是指被觀察的對象;具體目標是目標類的子類,通常它包含有經常發生改變的數據,當它的狀態發生改變時,向它的各個觀察者發出通知;觀察者將對觀察目標的改變做出反應;在具體觀察者中維護一個指向具體目標對象的引用,它存儲具體觀察者的有關狀態,這些狀態需要和具體目標的狀態保持一致。
觀察者模式的主要優點在于可以實現表示層和數據邏輯層的分離,并在觀察目標和觀察者之間建立一個抽象的耦合,支持廣播通信;其主要缺點在于如果一個觀察目標對象有很多直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間,而且如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。
本文已經收錄在系列文章Laravel源碼學習里,歡迎訪問閱讀。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/28804.html
摘要:對于包含通配符的事件名,會被統一放入數組中,是用來創建事件對應的的如果是監聽器是類,去創建監聽類創建的時候,會判斷監聽對象是監聽類還是閉包函數。對于閉包監聽來說,會再包裝一層返回一個閉包函數作為事件的監聽者。 事件系統 Laravel 的事件提供了一個簡單的觀察者實現,能夠訂閱和監聽應用中發生的各種事件。事件機制是一種很好的應用解耦方式,因為一個事件可以擁有多個互不依賴的監聽器。lar...
摘要:外觀模式的目的在于降低系統的復雜程度。在不引入抽象外觀類的情況下,增加新的子系統可能需要修改外觀類或客戶端的源代碼,違背了開閉原則。 外觀模式 外觀模式(Facade Pattern):外部與一個子系統的通信必須通過一個統一的外觀對象進行,為子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。外觀模式又稱為門面模式,它是一種對象結構型模...
摘要:解析出后將進入應用的請求對象傳遞給的方法,在方法負責處理流入應用的請求對象并返回響應對象。攜帶了本次迭代的值。通過這種方式讓請求對象依次流過了要通過的中間件,達到目的地的方法。 中間件(Middleware)在Laravel中起著過濾進入應用的HTTP請求對象(Request)和完善離開應用的HTTP響應對象(Reponse)的作用, 而且可以通過應用多個中間件來層層過濾請求、逐步完善...
摘要:系統的核心是由的認證組件的看守器和提供器組成。使用的認證系統,幾乎所有東西都已經為你配置好了。其配置文件位于,其中包含了用于調整認證服務行為的注釋清晰的選項配置。 用戶認證系統(基礎介紹) 使用過Laravel的開發者都知道,Laravel自帶了一個認證系統來提供基本的用戶注冊、登錄、認證、找回密碼,如果Auth系統里提供的基礎功能不滿足需求還可以很方便的在這些基礎功能上進行擴展。這篇...
摘要:過去一年時間寫了多篇文章來探討了我認為的框架最核心部分的設計思路代碼實現。為了大家閱讀方便,我把這些源碼學習的文章匯總到這里。數據庫算法和數據結構這些都是編程的內功,只有內功深厚了才能解決遇到的復雜問題。 過去一年時間寫了20多篇文章來探討了我認為的Larave框架最核心部分的設計思路、代碼實現。通過更新文章自己在軟件設計、文字表達方面都有所提高,在剛開始決定寫Laravel源碼分析地...
閱讀 3699·2021-11-11 16:55
閱讀 1646·2021-10-08 10:04
閱讀 3581·2021-09-27 13:36
閱讀 2761·2019-08-30 15:53
閱讀 1855·2019-08-30 11:17
閱讀 1259·2019-08-29 16:55
閱讀 2098·2019-08-29 13:57
閱讀 2513·2019-08-29 13:13