观察者模式

怎么理解?

从生活中例子来理解:

例子1:

员工1,员工2,员工3 ....;  老板 ;  前台同事;

员工1,2,3委托前台同事如果老板回来了,就通知他们几个;这里 员工就是观察者,收到通知后立即采取动作; 前台同事是被观察者,她的能力是添加通知对象(员工),移除某个“通知对象(员工)”,通知能力; 老板是触发前台通知的条件。

从常见的代码的业务逻辑来理解:

登录类,有时业务比较复杂,或者后期不断的需求增加如:加日志,加邮件通知,加IP过滤等等。都写在一个类中必然很庞大,易出错,难维护。 所以核心登录功能作为一个类(被观察者类); 加日志类,加邮件类等作为观察类。

php 代码如下:

<?php
/**
 * Created by PhpStorm.
 * User: zhaozhiliang
 * Date: 2018/6/6
 * Time: 上午10:57
 */

interface Observable{
    function attach(Observer $observer);
    function detach(Observer $observer);
    function notify();
}

class Login implements Observable {
    private $observers;
    const LOGIN_USER_UNKNOWN = 1;
    const LOGIN_WRONG_PASS =2;
    const LOGIN_ACCESS = 3;

    private $status = array();

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

    function attach(Observer $observer)
    {
        // TODO: Implement attach() method.
        $this->observers[] = $observer;
    }

    function detach(Observer $observer)
    {
        // TODO: Implement detach() method.
        $newobservers = array();
        foreach ($this->observers as $obs){
            if( $obs !== $observer){
                $newobservers[] = $obs;
            }
        }
        $this->observers = $newobservers;
    }

    function notify()
    {
        // TODO: Implement notify() method.
        foreach($this->observers as $obs){
            $obs->update($this);
        }
    }

    function handleLogin($user, $pass , $ip){

        /**
         *  实际上使用存储机制来验证用户数据。这个例子用rand()函数来模拟登录过程。
         */
        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 = false;
                break;
        }

        $this->notify();


        return $ret;
    }

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

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



}

interface Observer {
    function update(Observable $observable);
}

class SecurityMonitor implements Observer {
    function update(Observable $observable)
    {
        // TODO: Implement update() method.
        $status = $observable->getStatus();
        if($status[0] == Login::LOGIN_WRONG_PASS){
            //发送邮件给系统管理员
            print __CLASS__.":\tsending mail to sysadmin\n";
        }
    }
}

class GeneralLogger implements Observer{
    function update(Observable $observable)
    {
        // TODO: Implement update() method.
        $staus = $observable->getStatus();
        //记录登录数据到日志
        print __CLASS__.":\tadd login data to log\n";
    }
}

class PartnershipTool implements Observer{
    function update(Observable $observable)
    {
        // TODO: Implement update() method.
        $status = $observable->getStatus();
        print __CLASS__.":\tset cookie if IP matches a list\n";
    }
}


$login = new Login();
$login->attach(new SecurityMonitor());
$login->attach(new GeneralLogger());
$login->attach(new PartnershipTool());
$login->handleLogin('zhangsan','123456','127.0.0.1');


使用SPL库后的代码

<?php
/**
 *
 */

class Login implements SplSubject{
    private $storage;
    const LOGIN_USER_UNKNOWN = 1;
    const LOGIN_WRONG_PASS =2;
    const LOGIN_ACCESS = 3;

    private $status = array();

    function __construct()
    {
        $this->storage = new SplObjectStorage();
    }

    function attach(SplObserver $observer)
    {
        // TODO: Implement attach() method.
        $this->storage->attach($observer);
    }

    function detach(SplObserver $observer)
    {
        // TODO: Implement detach() method.
        $this->storage->detach($observer);
    }

    function notify()
    {
        // TODO: Implement notify() method.
        foreach ($this->storage as $obs){
            $obs->update($this);
        }
    }

    function handleLogin($user, $pass , $ip){

        /**
         *  实际上使用存储机制来验证用户数据。这个例子用rand()函数来模拟登录过程。
         */
        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 = false;
                break;
        }

        $this->notify();


        return $ret;
    }

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

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


abstract class LoginObserver implements SplObserver{
    private $login;
    function __construct(Login $login)
    {
        $this->login = $login;
        $login->attach($this);
    }

    function update(SplSubject $subject){
        if($subject === $this->login){
            $this->doUpdate($subject);
        }
    }

    abstract function doUpdate(Login $login);
}

class SecurityMonitor extends LoginObserver{
    function doUpdate(Login $login)
    {
        // TODO: Implement doUpdate() method.
        $status = $login->getStatus();
        if($status[0] == Login::LOGIN_WRONG_PASS){
            //发送邮件给系统管理员
            print __CLASS__.":\tsending mail to sysadmin\n";
        }

    }
}

class GeneralLogger extends LoginObserver{
    function doUpdate(Login $login)
    {
        // TODO: Implement doUpdate() method.
        $status = $login->getStatus();
        //记录登录数据到日志
        print __CLASS__.":\tadd login data to log\n";
    }
}

class PartnershipTool extends LoginObserver{
    function doUpdate(Login $login)
    {
        // TODO: Implement doUpdate() method.
        //检查IP地址
        //如果地址匹配则,设置cookie
        print __CLASS__.":\tset cookie if IP matches a list\n";
    }
}

$login = new Login();
//$login->attach(new SecurityMonitor($login));
new SecurityMonitor($login);

new GeneralLogger($login);

new PartnershipTool($login);
$login->handleLogin('zhangsan','123456','127.0.0.1');




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值