九、观察者模式
9.1 什么是观察者模式
观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe),它是一个在项目中经常使用的模式
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新
9.2 怎么实现观察者模式
Subject 被观察者:定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者;仅仅完成作为被观察者
必须实现的职责:管理观察者并通知观察者
Observer 观察者:观察者接收到消息后,对接收到的信息进行处理
ConcreteSubject 具体的被观察者:定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知
ConcreteObserver 具体的观察者:每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑
<?php
namespace Subject;
interface Observer
{
public function update();
}
class Observer1 implements Observer
{
public function update()
{
echo "Observer1 receive notify\n";
}
}
class Observer2 implements Observer
{
public function update()
{
echo "Observer2 receive notify\n";
}
}
abstract class Subject
{
private array $obs = [];
public function add(Observer $observer)
{
$key = $observer::class;
if (isset($this->obs[$key])) {
echo "observer is exist:{$key}\n";
} else {
$this->obs[$observer::class] = $observer;
echo "observer add success:{$key}\n";
}
}
public function del(Observer $observer)
{
$key = $observer::class;
if (isset($this->obs[$key])) {
unset($this->obs[$key]);
echo "remove observer:{$key} \n";
} else {
echo "the observer not exist:{$key}\n";
}
}
protected function noticeObserver()
{
if (count($this->obs) > 0) {
foreach ($this->obs as $observer) {
$observer->update();
}
}
}
}
class ConcreteSubject extends Subject
{
public function do()
{
echo "ConcreteSubject do something\n";
parent::noticeObserver();
}
}
$subject = new ConcreteSubject();
$obs1 = new Observer1();
$obs2 = new Observer2();
$subject->add($obs1);
$subject->add($obs2);
$subject->do();
//observer add success:Subject\Observer1
//observer add success:Subject\Observer2
//ConcreteSubject do something
//Observer1 receive notify
//Observer2 receive notify
echo "==============\n";
$subject->del($obs1);
$subject->do();
//remove observer:Subject\Observer1
//ConcreteSubject do something
//Observer2 receive notify
9.3 观察者模式优点是什么
- 观察者和被观察者之间是抽象耦合:不管是增加观察者还是被观察者都非常容易扩展
9.4 观察者模式缺点是什么
观察者模式需要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂
一个观察者卡壳,会影响整体的执行效率,所以一般都采用异步
9.5 观察者模式的注意事项
广播链的问题:一个观察者可以有双重身份,既是观察者,也是被观察者,这没什么问题呀,但是链一旦建立,
这个逻辑就比较复杂,可维护性非常差,根据经验建议,在一个观察者模式中最多出现一个对象既是观察者也是被观察者,
也就是说消息最多转发一次(传递两次),这还是比较好控制的
异步处理问题:异步处理就要考虑线程安全和队列的问题