Наблюдатель (англ. Observer ) - создаёт механизм подписки, с помощью которого одни объекты могут
подписываться на обновления, происходящие в других объектах во время выполнения программы.
Как только наблюдаемый объект меняется, он оповещает всех своих слушателей, чтобы они смогли среагировать на это изменение.
Для реализации публикации/подписки на поведение объекта, всякий раз, когда объект Subject
меняет свое состояние,
прикрепленные объекты Observers будут уведомлены. Шаблон используется, чтобы сократить количество связанных
напрямую объектов и вместо этого использует слабую связь (loose coupling ).
PHP предоставляет два стандартных интерфейса, которые могут помочь реализовать этот шаблон: SplObserver
и SplSubject
.
Newspaper.php
<?php
namespace DesignPatterns\Behavioral\Observer ;
use SplObserver ;
use SplSubject ;
/**
* Class Newspaper
* @package DesignPatterns\Behavioral\Observer
*/
class Newspaper implements SplSubject
{
/**
* @var string
*/
protected $name ;
/**
* @var SplObserver[]
*/
protected $observers = [];
/**
* @var string
*/
protected $content ;
/**
* Newspaper constructor.
*
* @param string $name
*/
public function __construct ( string $name )
{
$this -> name = $name ;
}
/**
* @param SplObserver $observer
*
* @return void
*/
public function attach ( SplObserver $observer )
{
array_push ( $this -> observers , $observer );
}
/**
* @param SplObserver $observer
*
* @return void
*/
public function detach ( SplObserver $observer )
{
$key = array_search ( $observer , $this -> observers , true );
if ( $key ) {
unset ( $this -> observers [ $key ]);
}
}
/**
* @param $content
*
* @return void
*/
public function breakOutNews ( $content )
{
$this -> content = $content ;
$this -> notify ();
}
/**
* @return string
*/
public function getContent (): string
{
return $this -> content . '( ' . $this -> name . ' )' ;
}
/**
* @return void
*/
public function notify ()
{
foreach ( $this -> observers as $value ) {
$value -> update ( $this );
}
}
}
Reader.php
<?php
namespace DesignPatterns\Behavioral\Observer ;
use SplObserver ;
use SplSubject ;
/**
* Class Reader
* @package DesignPatterns\Behavioral\Observer
*/
class Reader implements SplObserver
{
/**
* @var string
*/
protected $name ;
/**
* Reader constructor.
*
* @param string $name
*/
public function __construct ( string $name )
{
$this -> name = $name ;
}
/**
* @param SplSubject|Newspaper $subject
*/
public function update ( SplSubject $subject )
{
echo $this -> name . ' is reading breakout news ' . $subject -> getContent ();
}
}
Test case:
ObserverTest.php
<?php
namespace DesignPatterns\Tests\Behavioral\Observer ;
use DesignPatterns\Behavioral\Observer\Newspaper ;
use DesignPatterns\Behavioral\Observer\Reader ;
use PHPUnit_Framework_TestCase ;
class ObserverTest extends PHPUnit_Framework_TestCase
{
public function testPostedNewsAndUserNotify ()
{
$newspaper = new Newspaper ( 'New York Times' );
$allen = new Reader ( 'Allen' );
$newspaper -> attach ( $allen );
$newspaper -> breakOutNews ( 'Good news!' );
$this -> expectOutputString ( 'Allen is reading breakout news Good news!( New York Times )' );
}
}