[toc]
## 举个例子
> 老式热水器没有警报更没有自动切换模式的功能,所以烧热水必须得守着;不然时间长了成杀猪烫,时间短了又冷成狗。
> 智能热水器了:水烧好了就发一个警报,用户就可以直接去洗操了
## 代码示例
```php
<?php
class WaterHeater {
protected $observers;
protected $temperature;
public function __construct() {
$this->observers = array();
$this->temperature = 25;
}
public function getTemperature() {
return $this->temperature;
}
public function setTemperature($temperature) {
$this->temperature = $temperature;
echo "current temperature is {$this->temperature}\n";
$this->notifies();
}
public function addObserver($observers) {
array_push($this->observers, $observers);
}
public function notifies() {
foreach ($this->observers as $value) {
$value->update($this);
}
}
}
class Observer {
public function update($waterHeater) {
}
}
class WashingMode extends Observer {
public function update($waterHeater) {
if ($waterHeater->getTemperature() >= 50 && $waterHeater->getTemperature() < 70) {
echo "水已烧好,温度正好!可以用来洗澡了。" . PHP_EOL;
}
}
}
class DrinkingMode extends Observer {
public function update($waterHeater) {
if ($waterHeater->getTemperature() >= 100) {
echo "水烧开了, 可以喝了..." . PHP_EOL;
}
}
}
$heater = new WaterHeater();
$washingObser = new WashingMode();
$drinkingObser = new DrinkingMode();
$heater->addObserver($washingObser);
$heater->addObserver($drinkingObser);
$heater->setTemperature(40);
$heater->setTemperature(60);
$heater->setTemperature(100);
```
```
D:\soft\php72\php.exe D:\project\php_dp\index.php
current temperature is 40
current temperature is 60
水已烧好,温度正好!可以用来洗澡了。
current temperature is 100
水烧开了, 可以喝了...
Process finished with exit code 0
```
## 代码说明
1. 水烧到50-70度时,会发出警告:可以用来洗澡了!烧到100度也会发出警告:可以用来喝了!
1. 在这里洗澡模式和饮用模式扮演了监听的角色,而热水器则是被监听的对象。
1. 一旦热水器中的水温度发生变化,监听者都能及时知道并做出相应的判断和动作。
## UML图
![](https://box.kancloud.cn/43096fcb050eb5a0ca8504561c8f5683_527x334.png)
## 什么是监听模式
1. 监听模式又名观察者模式,顾名思意就是观察与被观察的关系
2. 比如你在烧开水得时时看着它开没开,你就是观察者,水就是被观察者
3. 再比如说你在带小孩,你关注她是不是饿了,是不是喝了,是不是撒尿了,你就是观察者,小孩就是被观察者。
4. 观察者模式一般是一种`一对多`的关系,可以有任意个(一个或多个)观察者对象同时监听某一个对象。
5. 监听的对象叫观察者,被监听的对象叫被观察者。
6. 被观察者对象在状态或内容发生变化时,会通知所有观察者对象,使它们能够做出相应的变化。
## 设计要点
1. 要明确谁是观察者谁是被观察者,只要明白谁是关注对象,问题也就明白了。
2. 一般观察者与被观察者之间是多对一的关系,一个被观察对象可以有多个监听对象(观察者)。如一个编辑框,有鼠标点击的监听者,也有键盘的监听者,还有内容改变的监听者。
3. `Observable` 在发送广播通知的时候,无须指定具体的 `Observer`,`Observer` 可以自己决定是否要订阅 `Subject` 的通知。
4. 被观察者至少需要有三个方法:`添加监听者`、`移除监听者`、`通知 Observer 的方法`;
5. 观察者至少要有一个方法:`更新方法`,更新当前的内容,作出相应的处理。
## 适用场景
1. 对一个对象状态或数据的更新需要其他对象同步更新,或者一个对象的更新需要依赖另一个对象的更新;
1. 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送。