## 定义
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖都会受到通知并自动更新。
## 设计原则
1. 为了交互对象之间的松耦合设计。
2. 观察者模式中,会改变的是主题的状态,以及观察者的数目的类型,利用这个模式,可以改变依赖于主题状态的对象,却不必改变主题。(<font color='red'>找出程序中会变化的方面,然后将其和固定不变的方面相分离</font>)
3. 主题与观察者都使用接口,观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者,这样可以让两者之间运作正常,又同时具备松耦合的优点。(<font color='red'>针对接口编程,不针对实现编程</font>)
## 使用场景
一个主题改变后需要通知不同类型的实体进行改变的场景。
## 实现要点
1. 定义观察者集合,并定义针对集合的添加、删除操作,用于增加、删除订阅者(观察者)
2. 定义通知方法,用于将新情况通知给观察者用户(订阅者用户)
## 补充
可以增加一个change状态来标识是否需要作出通知。
setChange(); // 设置为可通知
clearChange(); // 设置为不可通知
hasChange(); // 获取现在的标志位状态
## 代码示例
``` php
<?php
/**
* 被观察者接口
*/
interface Observable {
/**
* 添加/注册观察者
* @param Observer $observer 观察者对象
*/
public function attach(Observer $observer);
/**
* 删除观察者
* @param Observer $observer 观察者对象
*/
public function detach(Observer $observer);
/**
* 触发通知
*/
public function notify();
}
/**
* 观察者接口
*/
interface Observer {
// 接收到通知的处理方法
public function update(Observable $observable);
}
/**
* 被观察者实体
*/
class Video implements Observable {
// 订阅者
public $observers = [];
// 唱片名称
private $recordName;
// 唱片价格
private $recordPrice;
/**
* 构造方法
*/
public function __construct($recordName, $recordPrice)
{
$this->recordName = $recordName;
$this->recordPrice = $recordPrice;
}
/**
* 魔术方法 set
*/
public function __set($key, $value)
{
$this->$key = $value;
}
/**
* 魔术方法 get
*/
public function __get($key)
{
return $this->$key;
}
// 添加/注册观察者
public function attach(Observer $observer)
{
if(!in_array($observer, $this->observers)) {
$this->observers[] = $observer;
}
}
// 删除观察者
public function detach(Observer $observer)
{
$key = array_search($observer, $this->observers);
if($key === false) {
unset($this->observers[$key]);
}
}
// 触发通知
public function notify()
{
foreach ($this->observers as $observer) {
// 把本类对象传给观察者
$observer->update($this);
}
}
/**
* 发布
*/
public function publish()
{
$this->notify();
}
}
/**
* 观察者实体
*/
class LaoWang implements Observer {
public function update(Observable $observable){
echo '唱片名称:' . $observable->recordName . "<br/>" . '价格:' . $observable->recordPrice;
}
}
// 黑豹音乐唱片
$blackPanther = new Video('have no place', 18);
$laoWang = new LaoWang();
$blackPanther->attach($laoWang);
// 发布
$blackPanther->publish();
?>
```
本文章为读《HEAD FIRST 设计模式》笔记记录