观察者模式(又称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它是将行为独立模块化,下降了行为和主体的耦合性。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知全部的观察者对象,使他们可以自动更新本身。php
Subject:抽象主题(抽象被观察者),抽象主题角色把全部观察者对象保存在一个集合里,每一个主题均可以有任意数量的观察者,抽象主题提供一个接口,能够增长和删除观察者对象。模块化
ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给全部注册过的观察者发送通知。this
Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在获得主题更改通知时更新本身。code
ConcrereObserver:具体观察者,是实现抽象观察者定义的更新接口,以便在获得主题更改通知时更新自身的状态。server
PHP 内置了对象
SplSubject 抽象主题 Interface接口
SplObserver 抽象观察者 Interface事件
接口约束ip
// 主题 被观察者 interface SplSubject { public function attach(SplObserver $observer); //注册观察者到当前主题 public function detach(SplObserver $observer); //从当前主题删除观察者 public function notify(); //主题状态更新时通知全部的观察者作相应的处理 } // 观察者 interface SplObserver { public function update(SplSubject $subject); //注册观察者到当前主题 }
经过项目中的实际应用能更容易的去理解观察者模式开发
下面咱们以用户为主题,邮件模块和短信模块为观察者
当用户注册成功时,邮件观察者或短信观察者则收到相应的通知,发送邮件和短信给用户
User 主题
<?php /** * 主题类(被观察者至关于一个主题,观察者订阅这个主题) * 当咱们注册用户成功的时候想发送 email 和 sms 通知用户注册成功 * 则 能够将 SendEmail 和 SendSms 做为观察者 * 注册到 User 的观察者中 * 当 User register 成功时 notify 给 observers * 各 observe 经过约定的 update 接口进行相应的处理 发邮件或发短信 */ class User implements SplSubject { public $name; public $email; public $mobile; /** * 当前主题下的观察者集合 * @var array */ private $observers = []; /** * 模拟注册 * @param [type] $name [description] * @param [type] $email [description] * @param [type] $mobile [description] * @return [type] [description] */ public function register($name, $email, $mobile) { $this->name = $name; $this->email = $email; $this->mobile = $mobile; //business handle and register success $reg_result = true; if ($reg_result) { $this->notify(); // 注册成功 全部的观察者将会收到此主题的通知 return true; } return false; } /** * 当前主题注册新的观察者 * @param SplObserver $observer [description] * @return [type] [description] */ public function attach(SplObserver $observer) { return array_push($this->observers, $observer); } /** * 当前主题删除已注册的观察者 * @param SplObserver $observer [description] * @return [type] [description] */ public function detach(SplObserver $observer) { $key = array_search($observer, $this->observers, true); if (false !== $key) { unset($this->observers[$key]); return true; } return false; } /** * 状态更新 通知全部的观察者 * @return [type] [description] */ public function notify() { if (! empty($this->observers)) { foreach ($this->observers as $key => $observer) { $observer->update($this); } } return true; } }
Email/Sms 观察者
/** * 观察者经过 update 来接受主题的更新通知 */ class EmailObserver implements SplObserver { /** * 观察者接收主题通知的接口 * @param SplSubject $user [description] * @return [type] [description] */ public function update(SplSubject $user) { echo "send email to " . $user->email . PHP_EOL; } } class SmsObserver implements SplObserver { public function update(SplSubject $user) { echo "send sms to " . $user->mobile . PHP_EOL; } }
业务
// User 主题 $user = new User(); // 为 user 注册 Email 观察者 (Email 观察者订阅 User 主题) $emailObserver = new EmailObserver(); $user->attach($emailObserver); // 为 user 注册 Sms 观察者 (Sms 观察者订阅 User 主题) $smsObserver = new SmsObserver(); $user->attach($smsObserver); // 从 user 上删除 Sms 观察者 (Sms 观察者取消订阅 User 主题) //$user->detach($smsObserver); // register 中会根据注册结果通知观察者 观察者作相应的处理 $user->register("big cat", "32448732@qq.com", "1888888888");
结果
send email to 32448732@qq.com send sms to 1888888888 [Finished in 0.1s]
其实观察者模式相似于事件注册和钩子回调,平常开发中咱们可能重构分离出一部分类的行为到外部,封装成独立的功能模块,在注册到类中,能够使用事件注册,也能够使用观察者模式