PHP设计模式-观察者模式

观察者模式

问题引入

一个系统在用户登录的时候,经常要记录一些东西:session、登录次数、统计在线时长等;如果这么多的操作按照面向过程的方法编写,使一个对象变得复杂,它要操作这么多的事情,这样也违反单一功能原则。

如果这些操作以插件形式加载或移除,那么登录只完成它的单一功能操作。

  • 这样就可以使用观察者模式,后期再增加相关功能模块,不需要太多工作就可以加载同步;也不用修改登录的功能(符合开闭原则);
  • 缺点就是因为各个插件模块分散,后面功能可能重叠之前的功能,导致数据错误,所以在使用时要尽量注释或者整理好文档

使用场景

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。
  • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少个对象待改变。
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的

如何使用

php已经提供了主题接口类和观察者接口类,还有一个SplObjectStorage数据结构对象容器——实现了Countable,Iterator,Serializable,ArrayAccess四个接口。可实现统计、迭代、序列化、数组式访问等功能。

  • 主题类(被观察者)
namespace Observer;


use SplObjectStorage;
use SplObserver;
use SplSubject;

class User implements SplSubject
{
    /**
     * @var SplObjectStorage
     */
    private $observers;

    public function __construct()
    {
        $this->observers = new SplObjectStorage();
    }

    /**
     * Attach an SplObserver
     * @link http://php.net/manual/en/splsubject.attach.php
     * @param SplObserver $observer <p>
     * The <b>SplObserver</b> to attach.
     * </p>
     * @return void
     * @since 5.1.0
     */
    public function attach(SplObserver $observer)
    {
        $this->observers->attach($observer);
    }

    /**
     * Detach an observer
     * @link http://php.net/manual/en/splsubject.detach.php
     * @param SplObserver $observer <p>
     * The <b>SplObserver</b> to detach.
     * </p>
     * @return void
     * @since 5.1.0
     */
    public function detach(SplObserver $observer)
    {
        $this->observers->detach($observer);
    }

    /**
     * Notify an observer
     * @link http://php.net/manual/en/splsubject.notify.php
     * @return void
     * @since 5.1.0
     */
    public function notify()
    {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
}
  • 观察者1
namespace Observer;


use SplObserver;
use SplSubject;

class UserObserver implements SplObserver
{

    /**
     * Receive update from subject
     * @link http://php.net/manual/en/splobserver.update.php
     * @param SplSubject $subject <p>
     * The <b>SplSubject</b> notifying the observer of an update.
     * </p>
     * @return string
     * @since 5.1.0
     */
    public function update(SplSubject $subject)
    {
        echo '我是观察者1:获取用户信息' . '<br>';
    }
}
  • 观察者2
namespace Observer;


use SplSubject;

class OntimeObserver implements \SplObserver
{

    /**
     * Receive update from subject
     * @link http://php.net/manual/en/splobserver.update.php
     * @param SplSubject $subject <p>
     * The <b>SplSubject</b> notifying the observer of an update.
     * </p>
     * @return string
     * @since 5.1.0
     */
    public function update(SplSubject $subject)
    {
        echo '我是观察者2:记录用户在线时间' .'<br>';
    }
}
  • 实施调用

use Observer\OntimeObserver;
use Observer\User;
use Observer\UserObserver;

spl_autoload_register(function($class_name) {
    $class_file = realpath(dirname(__FILE__)."/../") .'/' . str_replace('\\','/', $class_name) . '.php';
    if (file_exists($class_file)) {
        include $class_file;
    } else {
        echo "加载文件失败";
    }
});

//实例化主题类
$user = new User();

//添加观察者
$user->attach(new UserObserver());
$user->attach(new OntimeObserver());

//通知观察者
$user->notify();
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 我是一名90后的未婚妈咪,我和他一开始由于年龄不够,未能领结婚证。刚订亲时,他对我挺好的。 每次回我家,他都买好多...
    娰悦阅读 5,121评论 40 47
  • 文/缪四儿 几天后的一个晚上,我独自睡在厨房的炕头上;我娘做晚饭把炕烧的温热,可夜半醒来总是觉得后背发冷。 我瑟缩...
    缪四儿阅读 2,688评论 0 11
  • 今天大寒。 一年中最冷的时节到了,春天也快来了。 独自坐在办公室里,心如止水,思绪起航。 有时,不折腾自己,不拼命...
    一帘思语阅读 1,346评论 0 0

友情链接更多精彩内容