php设计模式之观察者模式
理解观察者模式
观察者模式定义了对象之间一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
不知道大家有没有订杂志的经历,理解了订杂志的应用就能理解观察者模式。想想看,如果我们不去订阅杂志,那么我们想要看最新的杂志,就需要主动去商场或书店去看一看,运气好会有最新杂志买,运气不好的话就会空手而归。但如果我们去订阅了该杂志,那么我们就不需要去商场或书店了,只要有新的杂志,邮局就会主动给我们送过里。但我们取消订阅了,那我们就不在订阅者的名单上,邮局就不会给我们送上来。
观察者模式里有两种角色:发布者、订阅者
发布者需要提供的功能有:订阅、取消订阅、当有新的状态时通知订阅者。当有新的状态通知订阅者后,订阅者会进行相关操作。
应用场景及缺点
当一个对象状态的改变需要改变其他对象,或实际对象是事先未知的或动态变化的时,可使用观察者模式。
它的缺点是,通知的顺序无法保证。
实现观察者模式
首先我们看一个应用场景:当系统有新的用户注册时我们需要:
- 向用户发送信息通知
- 更新总用户数量
- 向用户赠送一张优惠券
UML类图
代码实现
PHP 已经定义了 2 个接口用于快速实现观察者模式:SplObserver 和 SplSubject。这里我们不用php提供的接口,自己来完成。
首先定义Observer接口
interface Observer
{
public function update ($userId);
}
然后是定义subject接口:
interface Subject
{
public function register (Observer $o);
public function remove (Observer $o);
public function notify ($info = null);
}
再实现具体的发布者:
class UserRegisterSubject implements Subject
{
private $observers = [];
// 订阅
public function register(Observer $o)
{
if (!in_array($o, $this->observers)) {
$this->observers[] = $o;
}
}
// 取消订阅
public function remove(Observer $o)
{
if (($k = array_search($o, $this->observers)) >= 0) {
unset($this->observers[$k]);
}
}
// 通知订阅者
public function notify($info = null)
{
foreach ($this->observers as $o) {
$o->update($info);
}
}
// 当有新用户注册时,触发notify方法
public function userAdd ($userId)
{
$this->notify($userId);
}
}
最后是订阅者的代码实现:
class Quan implements Observer
{
public function update($userId)
{
echo "向用户{$userId}发送一张新人优惠券".PHP_EOL;
}
}
class SendMsg implements Observer
{
public function update($userId)
{
echo "向用户{$userId}发送站内信".PHP_EOL;
}
}
class UserCnt implements Observer
{
public function update($userId)
{
echo '更新用户总数量'.PHP_EOL;
}
}
使用php已定义的接口快速实现
发布者代码
class UserRegisterSubject implements \SplSubject
{
private $observers = [];
private $userId = 0;
public function attach (\SplObserver $o)
{
if (!in_array($o, $this->observers)) {
$this->observers[] = $o;
}
}
public function detach(\SplObserver $o)
{
if (($k = array_search($o, $this->observers)) >= 0) {
unset($this->observers[$k]);
}
}
public function notify()
{
foreach ($this->observers as $o) {
$o->update($this);
}
}
// 当有新用户注册时,触发notify方法
public function userAdd ($userId)
{
$this->userId = $userId;
$this->notify();
}
public function getter ($key)
{
if (isset($this->$key)) {
return $this->$key;
}
}
}
订阅者代码:
class Quan implements \SplObserver
{
public function update(\SplSubject $sub)
{
echo "向用户{$sub->getter('userId')}发送一张新人优惠券".PHP_EOL;
}
}
class UserCnt implements \SplObserver
{
public function update(\SplSubject $sub)
{
echo '更新用户总数量'.PHP_EOL;
}
}
class SendMsg implements \SplObserver
{
public function update(\SplSubject $sub)
{
echo "向用户{$sub->getter('userId')}发送站内信".PHP_EOL;
}
}