PHP常用设计模式之观察者模式

概述

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式特点
观察者模式的初衷

将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、拓展和重用都带来不便。

观察者模式使用场景
  • 当一个对象的改变需要同时改变其他对象,并且它不知道具体有多少对象有待改变时
  • 当一个抽象模型有两个方面,其中一方面依赖于另一方面,这时使用观察者模式可以将这两者封装在独立的对象中使它们各自独立改变和复用。
代码实现

基于 PHP SPL 接口定义,实现观察者模式 UML图
UML

实现思路
  • UserSubject 类实现 SplSubject 接口,维护观察者列表(实现对观察者的添加和删除)并且通知观察者
  • UserObserver 类实现 SplObserver 接口,由 UserSubject 来通知的观察者类
具体代码:

UserSubject 实现 SplSubject 接口,实现对 Observer 对象的添加和删除,并通知 Observer 进行更新操作:

<?php

namespace DesignPattern\Observer;

class UserSubject implements \SplSubject {
    private $status;
    private $observers;

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

    public function attach(\SplObserver $observer) {
        $this->observers->attach($observer);
    }

    public function detach(\SplObserver $observer) {
        $this->observers->detach($observer);
    }

    public function setStatus($status) {
        $this->status = $status;
    }

    public function getStatus() {
        return $this->status;
    }

    public function notify() {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
}

UserObserver 实现 SplObserver 接口,更新操作的具体实现在其中:

<?php

namespace DesignPattern\Observer;

use \SplObserver;

class UserObserver implements SplObserver {
    private $name;
    private $observerStatus;

    public function __construct($name) {
        $this->name = $name;
    }

    public function update(\SplSubject $subject) {
        $this->observerStatus = $subject->getStatus();
        dump("$this->observerStatus changed, $this->name is notified.");
    }
}
测试文件:
<?php

namespace DesignPattern\Observer\Tests;

use PHPUnit\Framework\TestCase;
use DesignPattern\Observer\UserSubject;
use DesignPattern\Observer\UserObserver;

class TestObserver extends TestCase {
    public function testObserver() {
        $userSubject = new UserSubject();
        $userObserverOne = new UserObserver('小明');
        $userObserverTwo = new UserObserver('小白');
        $userObserverThree = new UserObserver('小红');

        $userSubject->attach($userObserverOne);
        $userSubject->attach($userObserverTwo);
        $userSubject->attach($userObserverThree);

        $userSubject->setStatus('user status');
        $userSubject->notify();

        $this->assertEquals(3, $userSubject->getObserversCount());
    }
}
测试结果:

测试结果

总结

优点:

  • 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
  • 观察者模式在观察目标和观察者之间建立一个抽象的耦合。
  • 观察者模式支持广播通信。
  • 观察者模式符合「开放封闭」原则。

缺点:

  • 在针对别人提供的模块,将无法实现观察者模式。
  • 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
参考文章

大话设计模式
图说设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值