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)
最新文章
- agsXMPP
- asp.net mvc 上传文件
- js声明json数据,打印json数据,遍历json数据
- iOS WebView调用JS的一个小坑
- FK JavaScript之:ArcGIS JavaScript添加Graphic,地图界面却不显示
- C#代码像QQ的右下角消息框一样,无论现在用户的焦点在哪个窗口,消息框弹出后都不影响焦点的变化,那么有两种方法
- Cocos2d-x解析XML文件,解决中文乱码
- BZOJ_1011_[HNOI2008]_遥远的行星_(近似)
- ClassLoader 工作机制
- 使用nginx作为websocket的proxy server
- 23 服务IntentService Demo6
- 如何使用ZOL一键安装器下载中关村在线的源安装包
- 【C++ mid-term exerises】
- matlab知识
- Python_装饰器_29
- Elasticsearch 基础知识要点与性能监控
- 洛谷P1219 八皇后【dfs】
- 题解 P1130 【红牌】
- matlib实现logistic回归算法(序一)
- 【校招面试 之 C/C++】第5题 C++各种构造函数的写法
热门文章
- NPM (node package manager) 入门 - 基础使用
- Cassandra简介
- Ubuntu 14.04中Elasticsearch集群配置
- 用html5的canvas和JavaScript创建一个绘图程序
- Vue-Router 页面正在加载特效
- C#开发微信门户及应用(39)--使用微信JSSDK实现签到的功能
- SSH框架和Redis的整合(2)
- Function.prototype.toString 的使用技巧
- mysql删除重复记录语句的方法
- Linux程序包管理之rpm