概述
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式特点
观察者模式的初衷
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、拓展和重用都带来不便。
观察者模式使用场景
- 当一个对象的改变需要同时改变其他对象,并且它不知道具体有多少对象有待改变时
- 当一个抽象模型有两个方面,其中一方面依赖于另一方面,这时使用观察者模式可以将这两者封装在独立的对象中使它们各自独立改变和复用。
代码实现
基于 PHP SPL 接口定义,实现观察者模式 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());
}
}
测试结果:
总结
优点:
- 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
- 观察者模式在观察目标和观察者之间建立一个抽象的耦合。
- 观察者模式支持广播通信。
- 观察者模式符合「开放封闭」原则。
缺点:
- 在针对别人提供的模块,将无法实现观察者模式。
- 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
参考文章
大话设计模式
图说设计模式