解析PHP观察者模式Observer

作者:phpyu 时间:2023-07-08 13:38:58 

观察者模式结构图

解析PHP观察者模式Observer

概念

一个"演员"(被观察者),一群"观众"(观察者),一台"摄影机"(记录容器)

【观察者模式中主要角色】

1.抽象主题(Subject)角色:主题角色将所有对观察者对象的引用保存在一个集合中,每个主题可以有任意多个观察者。 抽象主题提供了增加和删除观察者对象的接口。

2.抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在观察的主题发生改变时更新自己。

3.具体主题(ConcreteSubject)角色:存储相关状态到具体观察者对象,当具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。

4.具体观察者(ConcretedObserver)角色:存储一个具体主题对象,存储相关状态,实现抽象观察者角色所要求的更新接口,以使得其自身状态和主题的状态保持一致。

【使用场景】

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

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

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

【观察者模式与其它模式】

1.【中介者模式】(Mediator):通过封装复杂的更新语义,ChangeManager充当目标和观察者之间的中介者。
2.【单例模式】(singleton模式):ChangeManager可使用Singleton模式来保证它是唯一的并且是可全局访问的。

代码示例

接口示例


// 主题接口
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();

来源:https://www.cnblogs.com/phpyu/p/13526403.html

标签:php,观察者
0
投稿

猜你喜欢

  • JDBC下Idea添加mysql-jar包的详细过程

    2024-01-20 10:58:18
  • python模块之subprocess模块级方法的使用

    2022-05-10 03:28:32
  • 微信小程序时间轴实现方法示例

    2024-04-18 10:02:17
  • Dreamweaver MX 2004 之 Flash Element

    2010-03-25 12:27:00
  • python实现简单俄罗斯方块游戏

    2023-04-13 03:28:05
  • python实现PCA降维的示例详解

    2022-09-29 15:27:00
  • Oracle 数组的学习 小知识也要积累,养成好的学习态度

    2009-08-04 12:42:00
  • python脚本定时发送邮件

    2023-08-07 16:36:02
  • Pandas中常用的七个时间戳处理函数使用总结

    2023-05-28 21:41:33
  • vue中子组件调用兄弟组件方法

    2024-04-30 10:24:44
  • Flask框架踩坑之ajax跨域请求实现

    2023-12-25 01:28:02
  • js购物车实现思路及代码(个人感觉不错)

    2024-04-18 10:59:06
  • python并发编程多进程之守护进程原理解析

    2023-09-13 14:07:42
  • pandas库中 DataFrame的用法小结

    2021-08-11 00:54:01
  • Perl中的文件读写学习笔记

    2022-07-10 09:13:55
  • mysql利用参数sql_safe_updates限制update/delete范围详解

    2024-01-27 06:52:53
  • go语言beego框架web开发语法笔记示例

    2024-05-21 10:25:22
  • python DataFrame中stack()方法、unstack()方法和pivot()方法浅析

    2023-12-13 17:38:55
  • Python图像处理之透视变换的实战应用

    2022-08-16 17:22:10
  • Python中使用ConfigParser解析ini配置文件实例

    2021-06-18 01:41:44
  • asp之家 网络编程 m.aspxhome.com