近来在项目中需要使用到观察者模式去设计模块时,发现SPL标准库中已实现了观察者和被观察者的接口定义,这边直接拿来用就好。其实观察者模式中,被观察者无非就是需要先内置观察者绑定容器、绑定观察者(列表)、去除观察者(列表中)及通知已绑定的观察者状态改变这些操作。
首先先编写好被观察者类
/**
* 我的被观察者对象
* Class MySubject
*/
class MySubject implements SplSubject
{
/**
* 观察者对象数组
* @var SplObjectStorage
*/
private SplObjectStorage $observers;
/**
* 标签
* @var string
*/
private string $flag;
/**
* 构造方法中先实例出观察者对象数组
* MySubject constructor.
*/
public function __construct()
{
$this->observers = new SplObjectStorage();
}
/**
* 绑定观察者对象
* @param MyObserver $observer
*/
public function attach(SplObserver $observer) : void
{
$this->observers->attach($observer);
}
/**
* 把对象从观察者对象数组中去除(解绑)
* @param MyObserver $observer
*/
public function detach(SplObserver $observer) : void
{
if ($this->observers->offsetExists($observer)) {
$this->observers->detach($observer);
}
}
/**
* 通知状态改变
*/
public function notify() : void
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
/**
* 设置标签
* @param string $flag
*/
public function setFlag(string $flag) : void
{
$this->flag = $flag;
$this->notify();
}
/**
* 获取标签
* @return string
*/
public function getFlag() : string
{
return $this->flag;
}
}
接着编写观察者类
/**
* 我的观察者对象
* Class MyObserver
*/
class MyObserver implements SplObserver
{
/**
* 被观察者状态改变,则调用该通知
* @param MySubject $subject
*/
public function update(SplSubject $subject) : void
{
echo 'the new flag is ' . $subject->getFlag() . PHP_EOL;
}
}
最后在实际应用中将观察者与被观察者进行绑定,通过改变被观察者的状态,来达到它所绑定的观察者都能收到通知
// 实例化被观察者
$subject = new MySubject();
// 实例化观察者
$observer = new MyObserver();
// 注册观察行为
$subject->attach($observer);
// 改变标签(改变状态)
// 此时上一步注册后的观察者会收到改变状态的通知,从而执行对应的逻辑
$subject->setFlag('Hello');
观察者模式在实际应用场景中有很多,比如登陆后的短信、邮件通知,及重要操作时的日志记录(现在一般用AOP来实现更好)都可以用它来实现,让程序的可扩展性更高。