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