前言
换了一份新工作,新的环境,新的人,新的系统,新的代码(emmm)。
这两天没事,装装环境,看看代码。
在看到项目文件的时候,有了新的发现。
观察者模式
项目的优惠券类里使用了 观察者设计模式。原本这个也不算新奇,但是让我眼前一亮的是,优惠券类实现了 SplSubject 接口。
SplSubject 这个是什么接口?一看就知道是 PHP 提供的接口,但是作用却不清楚。
第一时间打开官网,找到这个接口的相关文档。
The SplSubject interface is used alongside SplObserver to implement the Observer Design Pattern.
SplSubject 接口是与 SplObserver 一起配合使用实现观察者设计模式的。
SplSubject {
abstract public void attach ( SplObserver $observer )
abstract public void detach ( SplObserver $observer )
abstract public void notify ( void )
}
从官网提供的信息可以看出,想要实现观察者设计模式还需要实现 SplObserver 接口。同时,需要实现 SplSubject 接口的三个方法。
下面是 SplObserver 在官方的释义。
SplObserver {
abstract public void update ( SplSubject $subject )
}
大概的实现如下:
class observer1 implements \SplObserver {
public function update(\SplSubject $subject)
{
echo 'I\'m observer1;';
}
}
class observer2 implements \SplObserver {
public function update(\SplSubject $subject)
{
echo 'I\'m observer2;';
}
}
class observer3 implements \SplObserver {
public function update(\SplSubject $subject)
{
echo 'I\'m observer3;';
}
}
class subject implements \SplSubject {
protected $observers = [];
public function attach(\SplObserver $observer)
{
$this->observers[] = $observer;
}
public function detach(\SplObserver $observer)
{
if ($key = array_search($observer, $this->observers)) {
unset($this->observers[$key]);
}
}
public function notify()
{
$observers = $this->observers;
foreach ($observers as $observer) {
$observer->update($this);
}
}
}
$observer1Cls = new observer1();
$observer2Cls = new observer2();
$observer3Cls = new observer3();
$subjectCls = new subject();
$subjectCls->attach($observer1Cls);
$subjectCls->attach($observer2Cls);
$subjectCls->attach($observer3Cls);
$subjectCls->notify();
# 输出:I\'m observer1;I\'m observer2;I\'m observer3;
$subjectCls->detach($observer2Cls);
$subjectCls->notify();
# 输出:I\'m observer1;I\'m observer3;
上述的实现方案也是项目中的实现方案,所有的观察者被放在一个类全局的数组中。
一般看手册的时候,会大致看一下人家是怎么使用的。就那么一看,看到了人家的实现方式,和自己有些出入,而且对于观察者的管理不是用的数组,而是用的是 PHP 官方提供的类 SplObjectStorage。
下面是官方对于 SplObjectStorage 类的释义:
The SplObjectStorage class provides a map from objects to data or, by ignoring data, an object set. This dual purpose can be useful in many cases involving the need to uniquely identify objects.
SplObjectStorage 类提供从对象到数据的映射,或者通过忽略数据提供对象集。这种双重用途在许多需要唯一标识对象的情况下是有用的。
SplObjectStorage implements Countable , Iterator , Serializable , ArrayAccess {
public void addAll ( SplObjectStorage $storage )
public void attach ( object $object [, mixed $data = NULL ] )
public bool contains ( object $object )
public int count ( void )
public object current ( void )
public void detach ( object $object )
public string getHash ( object $object )
public mixed getInfo ( void )
public int key ( void )
public void next ( void )
public bool offsetExists ( object $object )
public mixed offsetGet ( object $object )
public void offsetSet ( object $object [, mixed $data = NULL ] )
public void offsetUnset ( object $object )
public void removeAll ( SplObjectStorage $storage )
public void removeAllExcept ( SplObjectStorage $storage )
public void rewind ( void )
public string serialize ( void )
public void setInfo ( mixed $data )
public void unserialize ( string $serialized )
public bool valid ( void )
}
通过官网提供的信息,可以初步判断 SplObjectStorage 的使用方法。
下面是 SplSubject 手册中,一位网友提供的 观察者设计模式 的实现方案。
// Example implementation of Observer design pattern:
class MyObserver1 implements SplObserver {
public function update(SplSubject $subject) {
echo __CLASS__ . ' - ' . $subject->getName();
}
}
class MyObserver2 implements SplObserver {
public function update(SplSubject $subject) {
echo __CLASS__ . ' - ' . $subject->getName();
}
}
class MySubject implements SplSubject {
private $_observers;
private $_name;
public function __construct($name) {
$this->_observers = new SplObjectStorage();
$this->_name = $name;
}
public function attach(SplObserver $observer) {
$this->_observers->attach($observer);
}
public function detach(SplObserver $observer) {
$this->_observers->detach($observer);
}
public function notify() {
foreach ($this->_observers as $observer) {
$observer->update($this);
}
}
public function getName() {
return $this->_name;
}
}
$observer1 = new MyObserver1();
$observer2 = new MyObserver2();
$subject = new MySubject("test");
$subject->attach($observer1);
$subject->attach($observer2);
$subject->notify();
/*
will output:
MyObserver1 - test
MyObserver2 - test
*/
$subject->detach($observer2);
$subject->notify();
/*
will output:
MyObserver1 - test
*/
比起之前使用数组管理观察者的方式,SplSubjectStorage 的管理方式是比较优秀的,至于其他的一些不同和感受,目前没有太明确的感觉。
最后
这篇的篇幅不长,大部分的内容都来自于 PHP 官网,但自己的感触还是蛮深的。
本以为自己已经比较熟悉 PHP 的相关函数了,就算不知道的也是平常不常用的。
可现在感觉不同了,还是有很多好用的,我却忽略的函数和接口在默默奉献。
多看、多记、多思、多练,是提升自己的不二法门。
-- EOF --
本文转载自IMJCW
原文链接:PHP自带的观察者模式接口












网友评论