搜索
首页后端开发php教程了解观察者模式

Understanding the Observer Pattern

核心要点

  • 观察者模式是一种行为型设计模式,它在对象之间建立一对多的关系,当一个对象改变其状态时,所有依赖对象都会自动收到通知并更新。
  • 该模式包含一个主题(或发布者)和观察者(或订阅者)。主题通知观察者任何状态变化,观察者可以相应地采取行动。此模式促进松散耦合,使系统更灵活,更容易修改或扩展。
  • 观察者类提供一个update()方法,主题调用该方法以通知其状态变化。主题类定义主要方法:attach()detach()setState()notify(),用于管理观察者并通知他们状态变化。
  • 观察者模式适用于一个对象的更改需要更改其他对象的情况,尤其是在要更改的对象数量未知时。它可以用于在相关对象之间保持一致性,而无需紧密耦合它们。例如,它用于将门户的身份验证机制与论坛软件链接,允许用户使用单个登录名登录两者。

我最近被要求将第三方论坛软件集成到现有的 Web 门户中。问题是,这两个应用程序都有各自独立的身份验证机制。从用户的角度来看,理想情况下,用户无需单独登录论坛即可登录门户。在这种情况下,我不希望不必要地修改论坛代码,因为这会造成维护噩梦——我必须合并供应商的任何后续更新和错误修复,并小心避免覆盖我自己的修改。这就是观察者模式对我来说非常方便的地方。在本文中,我将向您展示如何实现观察者模式。您将学习模式中各种类如何相互关联作为主题和观察者,主题如何通知观察者其状态的变化,以及如何在您自己的代码中识别适合使用观察者模式的场景。

观察者模式

观察者模式(也称为发布-订阅模式)是一种行为型设计模式,它定义对象之间的一对多关系,以便当一个对象改变其状态时,所有依赖对象都会自动收到通知并更新。在我的例子中,我使用此模式将门户的身份验证机制与论坛软件链接。登录门户的行为也会自动触发用户登录论坛。与其他对自身状态感兴趣的对象具有一对多关系的对象称为主题发布者。其依赖对象称为观察者订阅者。每当主题的状态发生变化时,观察者都会收到通知,并可以相应地采取行动。主题可以拥有任意数量的依赖观察者,它会向这些观察者发出通知,并且任意数量的观察者都可以订阅主题以接收此类通知。

观察者类

观察者类提供一个update()方法,主题将调用该方法以通知其状态变化。在此示例中,我已将update()方法定义为具体方法。如果您愿意,您可以在此处将该方法定义为抽象方法,然后在观察者的子类中为其提供具体实现。

<?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));
        }
    }
}

__construct()方法接受可观察主题的实例,并将自身附加到主题——我稍后会讲到。update()方法检索主题的当前状态,并使用它来调用与状态名称相同的子类化观察者方法。因此,在我的特定情况下,我需要将门户现有的 Auth 类设为可观察主题,并创建一个具体的观察者子类来连接到论坛的身份验证代码。我的子类还需要使用主题的状态来实现方法。

主题类

主题类也是一个抽象类,它定义了四个主要方法:attach()detach()setState()notify()。为方便起见,我还在此处添加了getState()getObservers()方法。

<?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;
    }
}

attach()方法将观察者订阅到主题,以便可以向其传达任何状态更改。detach()方法将观察者从主题中取消订阅,以便它不再观察主题的状态更改。setState()方法设置主题的当前状态并调用notify()来更新观察者,即向每个观察者发布通知。notify()方法依次通过迭代内部列表并调用每个成员的update()方法来更新每个已订阅的对象。getState()getObservers()方法只是返回当前主题的状态和观察者列表的辅助函数。

仔细观察……整合在一起

现在有了观察者和主题的抽象基类,我能够将论坛软件集成到现有的 Web 门户中。我需要将门户的 Auth 类设为可观察主题,并在用户登录或注销门户时设置其可观察状态。

<?php
class Auth extends Subject
{
    function login() {
        // 执行登录身份验证的现有代码
        // ...

        // 向任何观察者发出信号,表明用户已登录
        $this->setState("login");
    }

    function logout() {
        // 执行用户注销时执行某些操作的现有代码
        // 例如销毁会话等...

        // 向任何观察者发出信号,表明用户已注销
        $this->setState("logout");
    }
}

我扩展了 Subject 类,以便 Auth 可观察,然后在 login()logout() 方法中添加了对 setState() 的调用。为了对观察者进行子类化,我创建了一个 Auth_ForumHook 类,该类负责调用论坛的 API 登录和注销函数。

<?php
class Auth_ForumHook extends Observer
{
    function login($subject) {
        // 调用论坛的 API 函数以登录用户
        // ...
    }

    function logout($subject) {
        // 调用论坛的 API 函数以注销用户
        // ...
    }
}

在代码库的其他地方,在实例化门户的 Auth 类的地方,我将 Auth_ForumHook 实例附加到它,以便观察者会收到 Auth 中任何状态更改的通知。

<?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));
        }
    }
}

除了准备抽象的 Observer 和 Subject 类之外,这就是我的额外编码需求的全部内容。Auth 的 login()logout() 方法触发的任何状态更改都会通知 Auth_ForumHook 观察者,并自动登录或注销论坛中的用户。要添加新的观察者,例如,登录跟踪器以记录用户何时登录或注销门户,只需提供一个具体的 Observer 类并将其附加到 Auth 主题即可,而无需进一步修改现有的 Auth 对象的 login()logout() 方法。

总结

如果您有多个依赖于另一个对象的对象,并且需要在该对象的状态发生变化时执行操作,或者一个对象需要通知其他对象而不知道它们是谁或有多少个,那么观察者模式是一个合适的适用设计模式。在本文中,我向您展示了基本的主题-观察者模式,并提供了具体的示例,说明如何使用这种行为模式轻松扩展现有类的功能,而无需紧密耦合任何新的需求。此模式使您能够在相关和依赖对象之间实现更高水平的一致性,而不会牺牲代码的可重用性。

图片来自 JPF / Shutterstock

(后续的FAQs部分,由于篇幅过长,已省略。核心内容已在上面重新组织和润色。)

以上是了解观察者模式的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
PHP记录:PHP日志分析的最佳实践PHP记录:PHP日志分析的最佳实践Mar 10, 2025 pm 02:32 PM

PHP日志记录对于监视和调试Web应用程序以及捕获关键事件,错误和运行时行为至关重要。它为系统性能提供了宝贵的见解,有助于识别问题并支持更快的故障排除

在Laravel中使用Flash会话数据在Laravel中使用Flash会话数据Mar 12, 2025 pm 05:08 PM

Laravel使用其直观的闪存方法简化了处理临时会话数据。这非常适合在您的应用程序中显示简短的消息,警报或通知。 默认情况下,数据仅针对后续请求: $请求 -

php中的卷曲:如何在REST API中使用PHP卷曲扩展php中的卷曲:如何在REST API中使用PHP卷曲扩展Mar 14, 2025 am 11:42 AM

PHP客户端URL(curl)扩展是开发人员的强大工具,可以与远程服务器和REST API无缝交互。通过利用Libcurl(备受尊敬的多协议文件传输库),PHP curl促进了有效的执行

简化的HTTP响应在Laravel测试中模拟了简化的HTTP响应在Laravel测试中模拟了Mar 12, 2025 pm 05:09 PM

Laravel 提供简洁的 HTTP 响应模拟语法,简化了 HTTP 交互测试。这种方法显着减少了代码冗余,同时使您的测试模拟更直观。 基本实现提供了多种响应类型快捷方式: use Illuminate\Support\Facades\Http; Http::fake([ 'google.com' => 'Hello World', 'github.com' => ['foo' => 'bar'], 'forge.laravel.com' =>

在Codecanyon上的12个最佳PHP聊天脚本在Codecanyon上的12个最佳PHP聊天脚本Mar 13, 2025 pm 12:08 PM

您是否想为客户最紧迫的问题提供实时的即时解决方案? 实时聊天使您可以与客户进行实时对话,并立即解决他们的问题。它允许您为您的自定义提供更快的服务

解释PHP中晚期静态结合的概念。解释PHP中晚期静态结合的概念。Mar 21, 2025 pm 01:33 PM

文章讨论了PHP 5.3中引入的PHP中的晚期静态结合(LSB),从而允许静态方法的运行时分辨率调用以获得更灵活的继承。 LSB的实用应用和潜在的触摸

自定义/扩展框架:如何添加自定义功能。自定义/扩展框架:如何添加自定义功能。Mar 28, 2025 pm 05:12 PM

本文讨论了将自定义功能添加到框架上,专注于理解体系结构,识别扩展点以及集成和调试的最佳实践。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器