介绍
定义:观察者模式(Observer)有时又被称为发布/订阅模式,当一个对象状态发生改变时,依赖它的对象全部会收到通知,并自动更新。
场景:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理逻辑。当更新的逻辑增加多之后,代码会变得难以维护。这种方式是耦合的,入侵式的,增加新的逻辑需要修改事件主体的代码。
特点:观察者模式实现了低耦合,非入侵式的通知与更新机制。
UML类图:
抽象观察者角色(IObserver):定义接到通知后所做的操作(Update)接口规则。
具体观察者角色(Log_Obsecer / Mail_Observer):实现具体操作方法。
抽象通知者角色(Exception_Notify):定义了通知的接口规则。
具体通知者角色(MyException):实现抽象通知者的接口,接到状态改变立即向观察者下发通知。
使用案例
本人在这里用观察者模式写一个异常捕获的通知功能,核心代码如下:
抽象观察者角色(IObserver)
// 定义观察者接口规范——观察者模式
interface IObserver{
public function update(Exception_Notify $e);
}
具体观察者角色1(Log_Obsecer)
// 具体观察者(日志通知)
class Log_Observer implements IObserver{
protected $_filename = './error.log';
public function __construct($filename=null) {
if($filename !==null && is_string($filename)){
$this->_filename = $filename;
}
}
public function update(Exception_Notify $e) {
$message = 'Time: '.date('Y-m-d H:i:s').PHP_EOL;
$message .= 'Info: '.$e->getMessage().PHP_EOL;
$message .= 'File: '.$e->getFile().PHP_EOL;
$message .= 'Line: '.$e->getLine().PHP_EOL;
error_log($message,3,$this->_filename);
}
}
具体观察者角色2(Mail_Observer)
// 具体观察者(邮箱通知)
class Mail_Observer implements IObserver {
protected $_email = '273788888@qq.com';
public function __construct($email=null) {
if($email !== null && filter_var($email,FILTER_VALIDATE_EMAIL)){
$this->_email = $email;
}
}
public function update(Exception_Notify $e) {
$message = 'Time: '.date('Y-m-d H:i:s').PHP_EOL;
$message .= 'Info: '.$e->getMessage().PHP_EOL;
$message .= 'File: '.$e->getFile().PHP_EOL;
$message .= 'Line: '.$e->getLine().PHP_EOL;
error_log($message,1,$this->_email);
}
}
抽象通知者角色(Exception_Notify)
class Exception_Notify extends Exception {
public static $_observer= [];
//关联观察者
public static function attach(IObserver $observer){
self::$_observer[] = $observer;
}
//移除观察者
public function detach(IObserver $observer){
foreach(self::$_observer as $k => $v){
if($v == $observer){
unset(self::$_observer[$k]);
}
}
}
//向观察者发送通知
public function notify(){
foreach(self::$_observer as $observer){
$observer->update($this);
}
}
}
具体通知者角色(MyException)
class MyException extends Exception_Notify{
public $_notifyName;
}
测试代码如下:
// 实例化一个通知者
$my_exception = new MyException();
//添加3个观察者
$my_exception::attach(new Log_Observer());
$my_exception::attach(new Mail_Observer());
$my_exception::attach(new Log_Observer('test.log'));
try{
throw new MyException('This is a test!!!');
}catch(Exception_Notify $e){
$e->notify();
}
运行结果:
上面的测试代码将会在同级目录生成两个日志文件,一个是默认的error.log还有一个是自定义的test.log;同时会向默认的邮箱273788888@qq.com发送相应的信息。
如对本例中异常的处理不是很理解,可以查看我的上一篇日志:PHP异常处理机制
——《完》——