解析PHP观察者模式Observer
作者:phpyu 发布时间:2023-07-08 13:38:58
观察者模式结构图
概念
一个"演员"(被观察者),一群"观众"(观察者),一台"摄影机"(记录容器)
【观察者模式中主要角色】
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


猜你喜欢
- 基础概念GoFrame框架(下文简称gf)提供的数据类型,比如:字典gmap、数组garray、集合gset、队列gqueue、树形结构gt
- 函数:startswith()作用:判断字符串是否以指定字符或子字符串开头一、函数说明语法:string.startswith(str, b
- 下面这段代码能够显示,当前用户所能够看到的所有的用户和表有兴趣的, 可以把每个表的内容加上<% Dim objOraSess
- v-for除了可以循环数组,还可以循环对象。例子:<template><div> <div v-for=&qu
- ASP中转换unicode编码为GB编码方法:<% function urldecode(encodestr)
- 用Open() 函数打开文件打开文件的常用方法是:open(FH, "< $filename") &nb
- 锁分类:从对数据操作的粒度分 :表锁:操作时,会锁定整个表。行锁:操作时,会锁定当前操作行。从对数据操作的类型分:读锁(共享锁):针对同一份
- 目录单例模式反射hasattergetattrsetattr总结单例模式一般情况下,类可以生成任意个实例,而单例模式只生成一个实例我们先用单
- 直接上代码图片就使用我家爽妹子的吧如果没有安装pil模块的话先cmd安装下输入:pip install pillow# -*- coding
- 在项目过程中,我们常常需要获取IP的所在地。而这一功能一般都是通过一些数据网站的对外接口来实现,这些接口一般情况下都是付费使用的。在这篇文章
- 在web运行中很重要的一个功能就是加载静态文件,在django中可能已经给我们设置好了,我们只要直接把模板文件放在templates就好了,
- 前言最近使用PyTorch感觉妙不可言,有种当初使用Keras的快感,而且速度还不慢。各种设计直接简洁,方便研究,比tensorflow的臃
- 众所周知,程序在启动后,各个程序文件都会被加载到内存中,这样如果程序文本再次变化,对当前程序的运行没有影响,这对程序是一种保护。但是,对于像
- 前段时间做一个小项目碰到了一个导航制作的方式然后突然想到曾经很久以前看到的梯形状的不规则导航,就尝试做了一下。结果碰到了几个问题,后来在同事
- 下面记录一下在本地 Windwos 环境用 vagrant 搭建的虚拟机(Homestaead)和生产环境阿里云 CentOS 系统安装 N
- 鲲之鹏的技术人员将在本文介绍一种通过模拟操作微信App的方式采集指定公众号的所有历史数据的方法。通过我们抓包分析发现,微信公众号的历史数据是
- 之前看到很多人一直都问这个问题,不过当时我没当一回事,因为在 CSS 中要垂直居中,多数是在有高度的情况下,或者容器高度不定的情况下才用,看
- 一、前言相关知识来自《python算法设计与分析》。初级排序算法是指几种较为基础且容易理解的排序算法。初级排序算法包括插入排序、选择排序和冒
- 上一篇讲到了javascript的节流函数和防抖函数,那么我们在实际场合中该如何运用呢?首先,我们来理解一下:节流函数首先是节流,就是节约流
- 1. lock互斥锁知识点:lock.acquire()# 上锁lock.release()# 解锁#同一时间允许一个进程上一把锁 就是Lo