SplSubject 接口

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

介绍

SplSubject 接口与 SplObserver 结合使用,以实现观察者设计模式。

接口概要

interface SplSubject {
/* 方法 */
public attach(SplObserver $observer): void
public detach(SplObserver $observer): void
public notify(): void
}

目录

添加备注

用户贡献的备注 4 个备注

przemyslaw dot szpiler at gmail dot com
12 年前
<?php

// 观察者设计模式的示例实现:

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();

/*
将输出:

MyObserver1 - test
MyObserver2 - test
*/

$subject->detach($observer2);
$subject->notify();

/*
将输出:

MyObserver1 - test
*/

?>
xedin dot unknown at gmail dot com
5 年前
几年来,我尝试了几次去理解 Subject/Observer 对背后的架构。最近我又试了一次。我无法想象为什么有人会以文档中描述的方式设计它。“他们当时在想什么?!”,我心想。如果 Subject 之外的东西可以告诉它何时通知观察者,那就会完全破坏封装。因为只有 Subject 才能知道它内部何时发生事件。因此,公开 `notify()` 将是对良好 OOP 设计原则的巨大违反。

但是,我想出了一个这种情况是有效的场景。也就是说,如果 Subject 代表一个钩子,就像 WordPress 中一样。例如,在一个事件系统中,事件以名称或代码调用,钩子可以代表系统中一个命名事件,通过从调度器外部调用 `notify()` 可以通知观察者。如果这是预期场景,那么问题主要出在命名上:“Subject” 这个名字暗示它是被观察的对象,而观察者模式是不同的。
匿名
11 年前
<?php
class Observable implements SplSubject
{
private
$storage;

function
__construct()
{
$this->storage = new SplObjectStorage();
}

function
attach(SplObserver $observer)
{
$this->storage->attach($observer);
}

function
detach(SplObserver $observer)
{
$this->storage->detach($observer);
}

function
notify()
{
foreach (
$this->storage as $obj) {
$obj->update($this);
}
}
//...
}

abstract class
Observer implements SplObserver
{
private
$observable;

function
__construct(Observable $observable)
{
$this->observable = $observable;
$observable->attach($this);
}

function
update(SplSubject $subject)
{
if (
$subject === $this->observable) {
$this->doUpdate($subject);
}
}

abstract function
doUpdate(Observable $observable);
}

class
ConcreteObserver extends Observer
{
function
doUpdate(Observable $observable)
{
//...
}
}

$observable = new Observable();
new
ConcreteObserver($observable);
aiddroid at example dot com
11 年前
/**
* 发布新闻的主体
*/
class Newspaper implements \SplSubject{
private $name;
private $observers = array();
private $content;

public function __construct($name) {
$this->name = $name;
}

// 添加观察者
public function attach(\SplObserver $observer) {
$this->observers[] = $observer;
}

// 移除观察者
public function detach(\SplObserver $observer) {

$key = array_search($observer,$this->observers, true);
if($key){
unset($this->observers[$key]);
}
}

// 设置突发新闻
public function breakOutNews($content) {
$this->content = $content;
$this->notify();
}

public function getContent() {
return $this->content." (by {$this->name})";
}

// 通知观察者(或部分观察者)
public function notify() {
foreach ($this->observers as $value) {
$value->update($this);
}
}
}

/**
* 接收新闻的观察者
*/
class Reader implements SplObserver{
private $name;

public function __construct($name) {
$this->name = $name;
}

public function update(\SplSubject $subject) {
echo $this->name.' 正在阅读突发新闻 <b>'.$subject->getContent().'</b><br>';
}
}

// 类测试
$newspaper = new Newspaper('纽约时报');

$allen = new Reader('艾伦');
$jim = new Reader('吉姆');
$linda = new Reader('琳达');

// 添加读者
$newspaper->attach($allen);
$newspaper->attach($jim);
$newspaper->attach($linda);

// 移除读者
$newspaper->detach($linda);

// 设置突发新闻
$newspaper->breakOutNews('美国崩溃!');

//=========输出==========
// 艾伦正在阅读突发新闻 美国崩溃! (by 纽约时报)
// 吉姆正在阅读突发新闻 美国崩溃! (by 纽约时报)
To Top