【读书笔记-重构与模式】 观察者模式--将客户元素从主体中分离

观察者模式的核心是把客户元素(观察者)从一个中心类(主体)中分离出来。当主体知道时间发生时,观察者需要被通知到。同时,不需要主体和观察者之间进行硬编码。

《设计模式》中对Observer模式的意图的描述是:“定义对象间的一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都能到得到通知并自动更新”

Observer模式用到的几条面向对象的原则也值得关注:

1.对象自我负责:Observer对象有多种,但是都从Subject对象手机所需信息,并自己完成相应的操作。

2.抽象类(接口):Observer类(接口)表示了“需要通知的对象”这一概念,它为目标提供了一个通知observer的公共接口。

3.多态封装:Subject并不知道与那种观察者通信。实际上,observer类封装了各种特定的observer.这以为这如果我在未来有新的observer,不需要更改subject类。


《深入php面向对象模式与实践》给给出的例子:

假设我们有一个login类处理用户的登陆信息,当用户登录时,根据用户的登录状态,做相应的动作。如果不对login对象和相应的动作做硬编码的话。observer模式是一个极佳的选择。

Observable 接口(主体):

interface Observable{
    function attach(Observer $observer);
    function detach(Observer $observer);
    function notify();
}
具体的Login(登录主体):
class login implements Observable{
    const LOGIN_ACCESS = 1;
    const LOGIN_WRONG_PASS = 2;
    const LOGIN_USER_UNKNOWN = 3;
    private $status = array();
    private $observers;

    public function __construct(){
        $this->observers = array();
    }

    public function attach(Observer $observer){
        $this->observers[] = $observer;
    }

    public function detach(Observer $observer){
        $newObservers = array();
        foreach($this->observers as $obs){
            if($obs != $observer){
                $newObservers[] = $obs;
            }
        }
        $this->observers = $newObservers;
    }

    private function setStatus($status,$user,$ip){
        $this->status = array($status,$user,$ip);
    }

    public function getStatus(){
        return $this->status;
    }

    public function notify(){
        foreach($this->observers as $obs){
            $obs->update($this);
        }
    }

    public function handlerLogin( $user,$pass,$ip){
        switch(rand(1,3)){
            case 1:
                $this->setStatus(Self::LOGIN_ACCESS,$user,$ip);
                $ret = true;break;
            case 2:
                $this->setStatus(Self::LOGIN_WRONG_PASS,$user,$ip);
                $ret = false;break;
            case 3:
                $this->setStatus(Self::LOGIN_USER_UNKNOWN,$user,$ip);
                $ret = true;break;
        }
    }
}

观察者接口:
interface Observer{
    function update(Observable $observable);
}

抽象的login观察者类:
abstract class LoginObserver implements Observer{
    private $login;

    public  function __construct(Login $login){
        $this->login = $login;
        $login->attach($this);
    }

    public function update(Observable $observable){
        if($observable == $this->login){
            $this->doUpdate($observable);
        }
    }

    abstract private function doUpdate( Login $login );
}

具体的观察者类:
//观察者1:登录失败时候发送邮件
class SecurityMonitor extends LoginObserver{
    private function doUpdate( Login $login ){
        $status = $login->getStatus();
        if($status[0] == Login::LOGIN_WRONG_PASS){
            print __CLASS__."\tsending mail to sysadmin";
        }
    }
}

//观察者2:记录登录日志
class GeneralLogger extends LoginObserver{
    private function doUpdate(Login $login){
        $status = $login->getStatus();
        //LOG
        print __CLASS__."[status]:{$status}\tadd login data to log";
    }
}

//观察者3:设置cookie
class PartnerShipTool extends LoginObserver{
    private function doUpdate(Login $login){
        $status = $login->getStatus();
        //COOKIE
        print __CLASS__."[Cookie]:{$status}\t set cookie to a list";
    }
}

各个类之间的类图关系如下图所示:


PHP内置的SPL扩展提供了对观察者模式的原生态支持。其中的观察者有三个元素组成,SplObserver,SplSubject,SplStorage.其中SplObserver,SplSubject都是接口。SplStorage是个工具类,用于更好滴储存对象和删除对象。



有SPL的支持,实现观察者模式更加方便一些了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值