设计模式之 —— 观察者模式

作者: 四月不见 | 来源:发表于2017-08-25 16:33 被阅读40次

    介绍

    定义:观察者模式(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异常处理机制

    ——《完》——

    相关文章

      网友评论

        本文标题:设计模式之 —— 观察者模式

        本文链接:https://www.haomeiwen.com/subject/eocudxtx.html