核心要點
update()
方法,主題調用該方法以通知其狀態變化。主題類定義主要方法:attach()
、detach()
、setState()
和notify()
,用於管理觀察者並通知他們狀態變化。 我最近被要求將第三方論壇軟件集成到現有的 Web 門戶中。問題是,這兩個應用程序都有各自獨立的身份驗證機制。從用戶的角度來看,理想情況下,用戶無需單獨登錄論壇即可登錄門戶。在這種情況下,我不希望不必要地修改論壇代碼,因為這會造成維護噩夢——我必須合併供應商的任何後續更新和錯誤修復,並小心避免覆蓋我自己的修改。這就是觀察者模式對我來說非常方便的地方。在本文中,我將向您展示如何實現觀察者模式。您將學習模式中各種類如何相互關聯作為主題和觀察者,主題如何通知觀察者其狀態的變化,以及如何在您自己的代碼中識別適合使用觀察者模式的場景。
觀察者模式
觀察者模式(也稱為發布-訂閱模式)是一種行為型設計模式,它定義對象之間的一對多關係,以便當一個對象改變其狀態時,所有依賴對像都會自動收到通知並更新。在我的例子中,我使用此模式將門戶的身份驗證機制與論壇軟件鏈接。登錄門戶的行為也會自動觸髮用戶登錄論壇。與其他對自身狀態感興趣的對象具有一對多關係的對象稱為主題或發布者。其依賴對象稱為觀察者或訂閱者。每當主題的狀態發生變化時,觀察者都會收到通知,並可以相應地採取行動。主題可以擁有任意數量的依賴觀察者,它會向這些觀察者發出通知,並且任意數量的觀察者都可以訂閱主題以接收此類通知。
觀察者類
觀察者類提供一個update()
方法,主題將調用該方法以通知其狀態變化。在此示例中,我已將update()
方法定義為具體方法。如果您願意,您可以在此處將該方法定義為抽象方法,然後在觀察者的子類中為其提供具體實現。
<code class="language-php"><?php abstract class Observer { public function __construct($subject = null) { if (is_object($subject) && $subject instanceof Subject) { $subject->attach($this); } } public function update($subject) { // 查找具有状态名称的观察者方法 if (method_exists($this, $subject->getState())) { call_user_func_array(array($this, $subject->getState()), array($subject)); } } }</code>
__construct()
方法接受可觀察主題的實例,並將自身附加到主題——我稍後會講到。 update()
方法檢索主題的當前狀態,並使用它來調用與狀態名稱相同的子類化觀察者方法。因此,在我的特定情況下,我需要將門戶現有的 Auth 類設為可觀察主題,並創建一個具體的觀察者子類來連接到論壇的身份驗證代碼。我的子類還需要使用主題的狀態來實現方法。
主題類
主題類也是一個抽像類,它定義了四個主要方法:attach()
、detach()
、setState()
和notify()
。為方便起見,我還在此處添加了getState()
和getObservers()
方法。
<code class="language-php"><?php abstract class Subject { protected $observers; protected $state; public function __construct() { $this->observers = array(); $this->state = null; } public function attach(Observer $observer) { $i = array_search($observer, $this->observers); if ($i === false) { $this->observers[] = $observer; } } public function detach(Observer $observer) { if (!empty($this->observers)) { $i = array_search($observer, $this->observers); if ($i !== false) { unset($this->observers[$i]); } } } public function getState() { return $this->state; } public function setState($state) { $this->state = $state; $this->notify(); } public function notify() { if (!empty($this->observers)) { foreach ($this->observers as $observer) { $observer->update($this); } } } public function getObservers() { return $this->observers; } }</code>
attach()
方法將觀察者訂閱到主題,以便可以向其傳達任何狀態更改。 detach()
方法將觀察者從主題中取消訂閱,以便它不再觀察主題的狀態更改。 setState()
方法設置主題的當前狀態並調用notify()
來更新觀察者,即向每個觀察者發布通知。 notify()
方法依次通過迭代內部列表並調用每個成員的update()
方法來更新每個已訂閱的對象。 getState()
和getObservers()
方法只是返回當前主題的狀態和觀察者列表的輔助函數。
仔細觀察……整合在一起
現在有了觀察者和主題的抽象基類,我能夠將論壇軟件集成到現有的 Web 門戶中。我需要將門戶的 Auth 類設為可觀察主題,並在用戶登錄或註銷門戶時設置其可觀察狀態。
<code class="language-php"><?php class Auth extends Subject { function login() { // 执行登录身份验证的现有代码 // ... // 向任何观察者发出信号,表明用户已登录 $this->setState("login"); } function logout() { // 执行用户注销时执行某些操作的现有代码 // 例如销毁会话等... // 向任何观察者发出信号,表明用户已注销 $this->setState("logout"); } }</code>
我擴展了 Subject 類,以便 Auth 可觀察,然後在 login()
和 logout()
方法中添加了對 setState()
的調用。為了對觀察者進行子類化,我創建了一個 Auth_ForumHook 類,該類負責調用論壇的 API 登錄和註銷函數。
<code class="language-php"><?php class Auth_ForumHook extends Observer { function login($subject) { // 调用论坛的 API 函数以登录用户 // ... } function logout($subject) { // 调用论坛的 API 函数以注销用户 // ... } }</code>
在代碼庫的其他地方,在實例化門戶的 Auth 類的地方,我將 Auth_ForumHook 實例附加到它,以便觀察者會收到 Auth 中任何狀態更改的通知。
<code class="language-php"><?php abstract class Observer { public function __construct($subject = null) { if (is_object($subject) && $subject instanceof Subject) { $subject->attach($this); } } public function update($subject) { // 查找具有状态名称的观察者方法 if (method_exists($this, $subject->getState())) { call_user_func_array(array($this, $subject->getState()), array($subject)); } } }</code>
除了準備抽象的 Observer 和 Subject 類之外,這就是我的額外編碼需求的全部內容。 Auth 的 login()
和 logout()
方法觸發的任何狀態更改都會通知 Auth_ForumHook 觀察者,並自動登錄或註銷論壇中的用戶。要添加新的觀察者,例如,登錄跟踪器以記錄用戶何時登錄或註銷門戶,只需提供一個具體的 Observer 類並將其附加到 Auth 主題即可,而無需進一步修改現有的 Auth 對象的 login()
和 logout()
方法。
總結
如果您有多個依賴於另一個對象的對象,並且需要在該對象的狀態發生變化時執行操作,或者一個對象需要通知其他對象而不知道它們是誰或有多少個,那麼觀察者模式是一個合適的適用設計模式。在本文中,我向您展示了基本的主題-觀察者模式,並提供了具體的示例,說明如何使用這種行為模式輕鬆擴展現有類的功能,而無需緊密耦合任何新的需求。此模式使您能夠在相關和依賴對象之間實現更高水平的一致性,而不會犧牲代碼的可重用性。
圖片來自 JPF / Shutterstock
(後續的FAQs部分,由於篇幅過長,已省略。核心內容已在上面重新組織和潤色。)
以上是了解觀察者模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!