PHP 高级编程(3/5) - 使用SPL(标准PHP库)实现观察者模式
SPL(标准PHP库 - Standard PHP Library)是PHP5面向对象功能中重要的部分。原文解释是这样的“The Standard PHP Library (SPL) is a collection of interfaces and classes that are meant to solve common problems”。
SplSubject 和 SplObserver 接口
The SplSubject interface is used alongside SplObserver to implement the Observer Design Pattern.
观察者模式是一种简单的事件系统,包含了两个或更多的互相交互的类。这一模式允许某个类观察另一个类的状态,当被观察类的状态发生变化时,这个模式会得到通知。被观察的类叫subject,负责观察的类叫做Observer 。PHP 提供的 SplSubject 和 SplObserver接口可用来表达这些内容。
SplSubject {
/* 方法 */
abstract public void attach ( SplObserver $observer )
abstract public void detach ( SplObserver $observer )
abstract public void notify ( void )
}
SplObserver {
/* 方法 */
abstract public void update ( SplSubject $subject )
}
这里,splsubject类维护了一个特定状态,当这个状态发生变化时,他就会调用notify方法,所以之前使用attach注册的splobserver实例的update就会被调用。这里我们实现一个简单地观察者模式的例子
<?php
/**
* Subject,that who makes news
*/
class Newspaper implements \SplSubject{
private $name;
private $observers = array();
private $content; public function __construct($name) {
$this->name = $name;
} //add observer
public function attach(\SplObserver $observer) {
$this->observers[] = $observer;
} //remove observer
public function detach(\SplObserver $observer) { $key = array_search($observer,$this->observers, true);
if($key){
unset($this->observers[$key]);
}
} //set breakouts news
public function breakOutNews($content) {
$this->content = $content;
$this->notify();
} public function getContent() {
return $this->content." ({$this->name})";
} //notify observers(or some of them)
public function notify() {
foreach ($this->observers as $value) {
$value->update($this);
}
}
} /**
* Observer,that who recieves news
*/
class Reader implements SplObserver{
private $name; public function __construct($name) {
$this->name = $name;
} public function update(\SplSubject $subject) {
echo $this->name.' is reading breakout news <b>'.$subject->getContent().'</b><br>';
}
} $newspaper = new Newspaper('Newyork Times'); $allen = new Reader('Allen');
$jim = new Reader('Jim');
$linda = new Reader('Linda'); //add reader
$newspaper->attach($allen);
$newspaper->attach($jim);
$newspaper->attach($linda); //remove reader
$newspaper->detach($linda); //set break outs
$newspaper->breakOutNews('USA break down!'); //=====output======
//Allen is reading breakout news USA break down! (Newyork Times)
//Jim is reading breakout news USA break down! (Newyork Times)
上例中我们通过数组存储 observer对象,使用数组及可能会出现两个问题:
1、同一个observer可能会被加载多次,导致多次调用同一个对象的update方法。
2、detach中需要通过迭代或者搜索数组来找到要删除的observer对象,导致运行效率降低。
SplObjectStorage类
PHP5提供了SplObjectStorage类,在这里我们可以用来存储observer对象,SplObjectStoraged的实例就像一个数组,但是他所存放的对象是唯一的。SplObjectStorage还可以使用detach直接从集合中删除指定的对象而不用遍历或搜索整个集合。下面看一个SplObjectStorage的例子:
<?php $ObjectStorage = new SplObjectStorage(); class classa
{
#code...
} class classb
{
#code...
} $a = new classa();
$b = new classb(); $ObjectStorage->attach($a);
$ObjectStorage->attach($b);
$ObjectStorage->attach($a); foreach ($ObjectStorage as $key => $item) {
echo ($key+).'、'.(new ReflectionClass($item))->getName()."\n";
} //output
1、classa
2、classb
[Finished in 0.1s]
?>
上例中我们可以看到,在ObjectStorage这个集合中只有1个calssa,尽管我们添加了两次。并且冲集合中删除一个元素也变得极为简单,拿上面的代码来说,只需使用$ObjectStorage->attach($a);即可轻松的将$a从集合中移除。
结合 SplObjectStorage 我们再来修改最上面那个观察者模式的例子
<?php
/**
* Subject,that who makes news
*/
class Newspaper implements \SplSubject{
private $name;
private $observers;
private $content; public function __construct($name) {
$this->name = $name;
$this->observers = new SplObjectStorage();
} //add observer
public function attach(\SplObserver $observer) {
$this->observers -> attach($observer);
} //remove observer
public function detach(\SplObserver $observer) {
$this->observers -> detach($observer);
} //set breakouts news
public function breakOutNews($content) {
$this->content = $content;
$this->notify();
} public function getContent() {
return $this->content." ({$this->name})";
} //notify observers(or some of them)
public function notify() {
foreach ($this->observers as $value) {
$value->update($this);
}
}
} /**
* Observer,that who recieves news
*/
class Reader implements SplObserver{
private $name; public function __construct($name) {
$this->name = $name;
} public function update(\SplSubject $subject) {
echo $this->name.' is reading breakout news '.$subject->getContent()."\n";
}
} $newspaper = new Newspaper('Newyork Times'); $allen = new Reader('Allen');
$jim = new Reader('Jim');
$linda = new Reader('Linda'); //add reader
$newspaper->attach($allen);
$newspaper->attach($jim);
$newspaper->attach($linda); //remove reader
$newspaper->detach($linda); //set break outs
$newspaper->breakOutNews('USA break down!'); //=====output======
//Allen is reading breakout news USA break down! (Newyork Times)
//Jim is reading breakout news USA break down! (Newyork Times)
PHP 高级编程(3/5) - 使用SPL(标准PHP库)实现观察者模式的更多相关文章
- UNIX环境高级编程 第2章 UNIX标准及实现
在过去的将近25年时间,人们为了UNIX的标准化做出了种种努力,这使得程序在不同版本的UNIX系统之间的移植相当容易. ISO C 1989年,C语言首个标准得到批准,其为C89.次年,一个带有小改动 ...
- (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- UNIX环境高级编程---标准I/O库
前言:我想大家学习C语言接触过的第一个函数应该是printf,但是我们真正理解它了吗?最近看Linux以及网络编程这块,我觉得I/O这块很难理解.以前从来没认识到Unix I/O和C标准库I/O函数压 ...
- UNIX环境高级编程笔记之标准I/O库
一.总结 文件I/O一章讲了不带缓冲的I/O,本章讲的是带缓冲的I/O.不带缓冲针对的是内核的系统调用,而带缓冲针对的是用户空间的标准库函数,是基于带缓冲的I/O实现的.不带缓冲的I/O通过文件描述符 ...
- 高级UNIX环境编程5 标准IO库
标准IO库都围绕流进进行的 <stdio.h><wchar.h> memccpy 一般用汇编写的 ftell/fseek/ftello/fseeko/fgetpos/fsetp ...
- 读《C#高级编程》第1章问题
读<C#高级编程>第1章 .Net机构体系笔记 网红的话:爸爸说我将来会是一个牛逼的程序员,因为我有一个梦,虽然脑壳笨但是做事情很能坚持. 本章主要是了解.Net的结构,都是一些概念,并没 ...
- (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- unix环境高级编程基础知识之第二篇(3)
看了unix环境高级编程第三章,把代码也都自己敲了一遍,另主要讲解了一些IO函数,read/write/fseek/fcntl:这里主要是c函数,比较容易,看多了就熟悉了.对fcntl函数讲解比较到位 ...
- (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
随机推荐
- Node.js:OS模块
os模块,可以用来获取操作系统相关的信息和机器物理信息,例如操作系统平台,内核,cpu架构,内存,cpu,网卡等信息. 使用如下所示: const os = require('os'); var de ...
- Asp.net Core 初探(发布和部署Linux)
前言 俗话说三天不学习,赶不上刘少奇.Asp.net Core更新这么长时间一直观望,周末帝都小雨,宅在家看了下Core Web App,顺便搭建了个HelloWorld环境来尝尝鲜,第一次看到.Ne ...
- WebApi返回Json格式字符串
WebApi返回json格式字符串, 在网上能找到好几种方法, 其中有三种普遍的方法, 但是感觉都不怎么好. 先贴一下, 网上给的常用方法吧. 方法一:(改配置法) 找到Global.asax文件,在 ...
- Maven搭建SpringMVC+Hibernate项目详解 【转】
前言 今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多了,Spring-Security的就留在下一篇吧,这 ...
- 手机游戏渠道SDK接入工具项目分享(二)万事开头难
一般接到任务后程序员们通常都开始着手进行技术调研了,但我这活是项目负责人.还有一大堆事情要先期准备,没人能帮忙. 一.人力配置 考虑的之前已经有一波人搞了大半年,但没有起色,先期也没有太大人力需求,所 ...
- android计算每个目录剩余空间丶总空间以及SD卡剩余空间
ublic class MemorySpaceCheck { /** * 计算剩余空间 * @param path * @return */ public static String getAvail ...
- FineReport:关于扩展行列求各种条件下的函数运用
最简单的扩展列,扩展行的求"最大,最小,平均"值的例子 设计图 效果图 相关函数 =MAX(B2:E2) =MIN(B2:E2) =AVERAGE(B2:E2) 这个是(满足条件) ...
- angular中使用ngResource模块构建RESTful架构
ngResource模块是angular专门为RESTful架构而设计的一个模块,它提供了'$resource'模块,$resource模块是基于$http的一个封装.下面来看看它的详细用法 1.引入 ...
- Hyper-V上运行的Linux虚拟机验证是否安装了集成服务
Hyper-V上运行的Linux虚拟机验证是否安装了集成服务 ps aux|grep "hv"root 311 0.0 0.0 0 0 ? ...
- 在Ubuntu13.04中配置Jexus+Mono3.2运行Asp.Net Mvc 4站点 (一)
这篇文章打算分两部分来写,第一部分介绍在Ubuntu中安装和配置.Net Framework4.5环境,第二部分介绍如何部署Asp.Net Mvc 4站点并确保Mvc4的几个重要特性都能正常工作. 一 ...