### 定义
又称为发布-订阅(Publish-Subscribe)模式,一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象使它们能够自动更新自己。
### 作用
一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
### 使用场景
购票成功通知。
### 优、缺点
优点:
1. 观察者和被观察者是抽象耦合的;
2. 建立一套触发机制。
缺点:
1. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;
2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;
3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
### 模式结构
:-: ![](https://box.kancloud.cn/4aeca3ebf591cae7387b6aa92da72047_417x297.bmp)
### 示例类图
建造者模式包含几个角色:
* 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 微信通知:购票成功:<中影电影院>一排一号
```
* * * * *
### 注意事项
(略)