[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圖

## 什么是監聽模式
1. 監聽模式又名觀察者模式,顧名思意就是觀察與被觀察的關系
2. 比如你在燒開水得時時看著它開沒開,你就是觀察者,水就是被觀察者
3. 再比如說你在帶小孩,你關注她是不是餓了,是不是喝了,是不是撒尿了,你就是觀察者,小孩就是被觀察者。
4. 觀察者模式一般是一種`一對多`的關系,可以有任意個(一個或多個)觀察者對象同時監聽某一個對象。
5. 監聽的對象叫觀察者,被監聽的對象叫被觀察者。
6. 被觀察者對象在狀態或內容發生變化時,會通知所有觀察者對象,使它們能夠做出相應的變化。
## 設計要點
1. 要明確誰是觀察者誰是被觀察者,只要明白誰是關注對象,問題也就明白了。
2. 一般觀察者與被觀察者之間是多對一的關系,一個被觀察對象可以有多個監聽對象(觀察者)。如一個編輯框,有鼠標點擊的監聽者,也有鍵盤的監聽者,還有內容改變的監聽者。
3. `Observable` 在發送廣播通知的時候,無須指定具體的 `Observer`,`Observer` 可以自己決定是否要訂閱 `Subject` 的通知。
4. 被觀察者至少需要有三個方法:`添加監聽者`、`移除監聽者`、`通知 Observer 的方法`;
5. 觀察者至少要有一個方法:`更新方法`,更新當前的內容,作出相應的處理。
## 適用場景
1. 對一個對象狀態或數據的更新需要其他對象同步更新,或者一個對象的更新需要依賴另一個對象的更新;
1. 對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節,如消息推送。