Спостерігач (англ. 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 )' );
}
}