zoukankan      html  css  js  c++  java
  • PHP设计模式之观察者模式

    使用场景

    假设项目经理让我们写了一个登陆接口,咔咔擦擦写完了

    • 第二天让我们加入统计登陆次数,然后在后面加代码
    • 第三天让我们判断登陆地区,又在后面加代码
    • 第四天让我们在用户登陆后推送活动,再再后面加代码
    • 第N天,这个接口已经杂乱到没人想维护了

    我们需要让项目保持高内聚低耦合,就可以用到观察者模式(也不是非要,看需求)

    概念

    观察者,观察者,首先要有个被人观察的角色,这是唯一的,然后会有无数个观察者去看她,可以说是一群人在围观一个人,既然有无数个观众,那总得有个东西记录有哪些观察者,那就应该有一个类似于数组一样来储存所有观察者,总结就是一个被观察者,无数个观察者,再有一个容器记录

    代码示例

    • 接口示例
    // 主题接口
    interface Subject{
        public function register(Observer $observer);
        public function notify();
    }
    // 观察者接口
    interface Observer{
        public function watch();
    }
    

    Subject就是被观察者,Observer就是观众,也就是观察者

    被观察者

    // 被观察者
    class Action implements Subject{
         public $_observers=array();
         public function register(Observer $observer){
             $this->_observers[]=$observer;
         }
     
         public function notify(){
             foreach ($this->_observers as $observer) {
                 $observer->watch();
             }
     
         }
     }
    

    Action实现了被观察者接口,他现在就是被观察者,再定义一个$_observers数组,他就是记录观众的容器了。
    首先实现register方法,用它传入一个观察者,然后塞到数组里,再实现notify()方法,它会遍历容器数组,执行每个观察者的watch()方法。

    观察者

    // 观察者
    class Cat implements Observer{
         public function watch(){
             echo "Cat watches TV<hr/>";
         }
     }
     class Dog implements Observer{
         public function watch(){
             echo "Dog watches TV<hr/>";
         }
     }
     class People implements Observer{
         public function watch(){
             echo "People watches TV<hr/>";
         }
     }
    

    这里定义了三个观察者,全都实现了Observer接口,前面的Subject会循环调用每个观察者的watch()方法,所以我们需要实现每个观察者的watch()方法。

    调用

    // 应用实例
    $action=new Action();
    $action->register(new Cat());
    $action->register(new People());
    $action->register(new Dog());
    $action->notify();
    

    首先new被观察者对象,执行它的register()方法,把每个观察者都放入容器数组,最后执行notify()方法,通知所有观察者执行自己的方法。

    PHP原生自带的观察者模式

    PHP有自带的观察者模式

    • splsubject接口 - 被观察者
    • Observer接口 - 观察者
    • SplObjectStorage对象 - 容器

    首先我们有一个用户登录类

    class user{
    
      public function login()
      {
      	echo '登录完毕'
      }
    

    让他实现splsubject接口成为被观察者。

    • 首先在构造函数里,让他new SplObjectStorag()对象并赋值到属性上方便后面调用
    • 实现attach()方法,用来注册观察者
    • 实现detach()方法,用来删除观察者
    • 实现notify()方法,用来遍历容器,调用每个观察者的update方法(必须是update)
    • rewind方法是容器指针重置到最开始,valid方法检测容器是否遍历完成并返回布尔,current方法是获取当前的观察者,next方法是将指针后移一位
    • 修改login()方法,在里面调用notify()来通知观察者事件完成了
    class user implements splsubject{
    
        protected $observer = null;
    
        public function __construct()
        {
            $this->observer = new SplObjectStorage();
        }
    
        public function login()
        {
            $this->notify();
            echo '登录完毕';
        }
    
        public function attach(SplObserver $observer)
        {
            $this->observer->attach($observer);
        }
    
        public function detach(SplObserver $observer)
        {
            $this->observer->detach($observer);
        }
    
        public function notify()
        {
            $this->observer->rewind();
            while ($this->observer->valid())
            {
                $observer = $this->observer->current();
                $observer->update($this);
                $this->observer->next();
            }
        }
    }
    

    观察者

    每个观察者实现SplObserver接口,并实现update()方法

    class cat implements SplObserver {
    
        public function update(SplSubject $subject)
        {
            echo '小猫叫一下';
        }
    }
    class dog implements SplObserver {
        public function update(SplSubject $subject)
        {
            echo '小狗吼一声';
        }
    }
    

    应用

    // 实时观察
    $user = new user();
    $user->attach(new cat());
    $user->attach(new dog());
    $user->login();
    
  • 相关阅读:
    【学习总结】SQL学习总结之SQL语法
    【学习总结】SQL学习总结之认识SQL
    【JAVA】JAVA8-String.join字符串拼接
    【JAVA】Scanner.next()与Scanner.nextLine()的区别
    【JAVA】java中split以"." 、""、“|”分隔字符串
    【问题解决方案】apple music取消订阅
    【问题解决方案】MacBook Pro那些坑
    【JAVA】Java循环语句中的continue跳转进入下一次循环是否判断循环条件
    【问题解决方案】Markdown中部分字符显示为格式因而得不到预期结果的问题解决
    【JAVA】哈希表HashMap中java8新增功能概述
  • 原文地址:https://www.cnblogs.com/cxfs/p/13412923.html
Copyright © 2011-2022 走看看