### 定義
又稱為發布-訂閱(Publish-Subscribe)模式,一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象使它們能夠自動更新自己。
### 作用
一個對象(目標對象)的狀態發生改變,所有的依賴對象(觀察者對象)都將得到通知,進行廣播通知。
### 使用場景
購票成功通知。
### 優、缺點
優點:
1. 觀察者和被觀察者是抽象耦合的;
2. 建立一套觸發機制。
缺點:
1. 如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間;
2. 如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰;
3. 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎么發生變化的,而僅僅只是知道觀察目標發生了變化。
### 模式結構
:-: 
### 示例類圖
建造者模式包含幾個角色:
* Subject:抽象主題接口,它把所有觀察者對象的引用保存到一個聚集里,每個主題都可以有任何數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象。
* ConcreteSubject:被觀察對象接口將有關狀態存入具體觀察者對象;在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。
* Observer:抽象觀察者類,為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。
* ConcreteObserver:具體觀察者類,實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題狀態協調。
### 示例代碼
* 抽象主題接口(Subject)
```
/**
* 觀察者接口(通知接口)
*/
interface ITicketObserver
{
function onBuyTicketOver($sender, $args); //得到通知后調用的方法
}
```
* ()
```
/**
* 主題接口
*/
interface ITicketObservable
{
function addObserver($observer); //提供注冊觀察者方法
function delObserver($observer); //提供刪除觀察者方法
}
```
* ()
```
/**
* 主題類(購票)
*/
class HipiaoBuy implements ITicketObservable { // 實現主題接口(被觀察者)
private $_observers = array (); // 通知數組(觀察者)
public function buyTicket($ticket) // 購票核心類,處理購票流程
{
// TODO 購票邏輯
// 循環通知,調用其onBuyTicketOver實現不同業務邏輯
foreach ( $this->_observers as $obs ) {
$obs->onBuyTicketOver ( $this, $ticket ); // $this 可用來獲取主題類句柄,在通知中使用
}
}
// 添加通知對象、添加N個通知
public function addObserver($observer)
{
$this->_observers [] = $observer;
}
// 移除通知對象
public function delObserver($observer)
{
$index = array_search($observer, $this->_observers);
if($index >= 0) {
array_splice($this->_observers, $index, 1);
}
}
}
```
* 定義多個通知()
```
//短信通知
class HipiaoMSM implements ITicketObserver {
public function onBuyTicketOver($sender, $ticket) {
echo (date ( 'Y-m-d H:i:s' ) . " 短信通知:購票成功:$ticket\n");
}
}
//郵件通知
class HipiaoMail implements ITicketObserver {
public function onBuyTicketOver($sender, $ticket) {
echo (date ( 'Y-m-d H:i:s' ) . " 郵件通知:購票成功:$ticket\n");
}
}
//微信通知
class HipiaoWeixin implements ITicketObserver {
public function onBuyTicketOver($sender, $ticket) {
echo (date ( 'Y-m-d H:i:s' ) . " 微信通知:購票成功:$ticket\n");
}
}
```
* 客戶端調用
```
class Client
{
public static function main($argv)
{
$buy = new HipiaoBuy ();
$buy->addObserver ( new HipiaoMSM() ); //根據不同業務邏輯加入各種通知
$buy->addObserver ( new HipiaoMail() );
$buy->addObserver ( new HipiaoWeixin() );
$buy->delObserver ( new HipiaoMail() );
//購票
$buy->buyTicket ( "<中影電影院>一排一號" );
}
}
Client::main($argv);
```
* 運行結果
```
2018-05-17 16:51:00 短信通知:購票成功:<中影電影院>一排一號
2018-05-17 16:51:00 微信通知:購票成功:<中影電影院>一排一號
```
* * * * *
### 注意事項
(略)