什么是观察者模式
观察者模式,属于行为型模式。观察者模式有时也被称作发布/订阅模式,该模式用于为对象实现发布/订阅功能:一旦主体对象状态发生改变,与之关联的观察者对象会收到通知,并进行相应操作。
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。 消息队列系统、事件都使用了观察者模式。
PHP 为观察者模式定义了两个接口:SplSubject 和 SplObserver。
SplSubject 可以看做主体对象的抽象,SplObserver 可以看做观察者对象的抽象,要实现观察者模式,只需让主体对象实现 SplSubject ,观察者对象实现 SplObserver,并实现相应方法即可。
应用场景
跟发布/订阅类似,某些场景的改变需要通知其相关的模块做出相应改变,比如订单下单成功需要通知库存模块减库存、通知信息通知模块发送验证码、日志的记录等。
PHP 代码实现
<?php
/**
* 观察者模式 : 被观察对象 (主体对象)
* 主体对象维护观察者列表并发送通知
* Class User
*/
class User implements SplSubject
{
/**
* 参数数据
* user data
* @var array
*/
protected $data = array();
/**
* 观察者对象
* observers
* @var SplObjectStorage
*/
protected $observers;
public function __construct()
{
$this->observers = new SplObjectStorage();
}
/**
* 注册观察者
* @param SplObserver $observer
* @return void
*/
public function attach(SplObserver $observer)
{
$this->observers->attach($observer);
}
/**
* 移除观察者
* @param SplObserver $observer
* @return void
*/
public function detach(SplObserver $observer)
{
$this->observers->detach($observer);
}
/**
* 通知观察者方法
*
* @return void
*/
public function notify()
{
/**
* @var SplObserver $observer
*/
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
/**
* 设置参数
* @param $name string 参数索引
* @param $value string 参数值
* @return void
*/
public function __set($name, $value)
{
$this->data[$name] = $value;
// 通知观察者用户被改变
$this->notify();
}
}
/**
* 观察者对象
* Class UserObserver
*/
class UserObserver implements \SplObserver
{
/**
* 观察者要实现的唯一方法
* 也是被 Subject 调用的方法
* @param SplSubject $subject
*/
public function update(SplSubject $subject)
{
echo get_class($subject) . ' has been updated';
}
}
//=======================观察者调用===============================
//测试通知
$subject = new User();
$observer = new UserObserver();
$subject->attach($observer);
//触发__set
$subject->id = '1126';
echo '<hr>';//横线
//测试订阅
$subject = new User();
$subject->attach($observer);
$subject->detach($observer);
echo '已订阅';
echo '<hr>';//横线
//测试 update() 调用
$subject = new User();
$subject->attach($observer);
$subject->notify();
//结果
//User has been updated
//已订阅
//User has been updated
参考资料:
https://xueyuanjun.com/post/2935