Рассматривается поведенческий шаблон проектирования Observer, приводится пример его реализации в интернет-магазине.
Содержание
- Применение
- Реализация
- Итоги
Применение
Сегодня рассмотрим достаточно простой, но важный поведенческий шаблон проектирования Observer. На примере магазина покажем, как его можно применить. Для этого представьте, что вы хотите, чтобы пользователи могли отслеживать товар в вашем продвинутом интернет магазине. Состав таких подписчиков на товар ежедневно естественно изменяется. Что мы имеем? Магазину должен оповещать всех заинтересованных покупателей об изменениях в состоянии товаров, а вам хотелось бы отслеживать, какой товар пользуется популярностью. Чтобы знать этих заинтересованных, надо дать им возможность подписываться и отписываться на товары. В этом случае магазин без проблем реализует подписку на свои товары. Вот этим и займёмся с помощью шаблона Observer.
Реализация
В реализации шаблона будут использоваться такие компоненты.
- интерфейс IObservable — определяет набор методов, с помощью которых подписчики могут управлять подпиской на товар;
- интерфейс IObserver — определяет метод для отслеживания извещений подписчиков;
- Класс Goods — товар, в числе прочего реализует интерфейс IObservable;
- класс Customer — определяет функционал покупателя и выступает в роли наблюдателя, реализует интерфейс IObserver.
Начнем естественно с интерфейсов. Определим функции, необходимые для реализации возможности подписки.
interface IObservable
{
public function attach(IObserver $observer): void;
public function detach(IObserver $observer): void;
public function notify(): void;
}
Теперь задекларируем метод, которым будем отслеживать изменения в магазине.
interface IObserver
{
public function update(IObservable $subject): void;
}
Интерфейс IObservable реализован в классе товара. При поступлении нового события товар будет извещать об этом подписанных на него клиентов.
class Goods implements IObservable
{
private string $name;
private string $event = 'state1';
/** @var Observer[] */
private array $observers = [];
public function __construct(string $name)
{
$this->name = $name;
}
public function attach(IObserver $observer): void
{
$this->observers[spl_object_id($observer)] = $observer;
}
public function detach(IObserver $observer): void
{
unset($this->observers[spl_object_id($observer)]);
}
public function notify(): void
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function setEvent(string $event): void
{
$this->event = $event;
$goods = $this->getName();
echo '<br>Товар ' . $goods . ' изменил свое состояние.';
$this->notify();
}
public function getName(): string
{
return $this->name;
}
public function getEvent(): string
{
return $this->event;
}
}
Класс Customer в примере выступает в роли наблюдателя. Он должен отработать поступившее сообщение, в нашем примере он просто сообщает о получении извещения в методе notify().
class Customer implements IObserver
{
private string $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function update(IObservable $subject): void
{
if ($subject instanceof Goods) {
/*
функционал, извещающий наблюдателя об изменениях в товаре $subject
*/
// сообщение администратору о изменениях
$msg = "<br> Клиент <i>{$this->name}</i> получил сообщение <i>{$subject->getEvent()}</i> "
. "об изменении статуса товара {$subject->getName()}\n";
}
}
}
Выше приведён упрощенный код шаблона. Известить клиентов и администратора об изменениях, можно, например, через БД.
$goods = new Goods('Товар1');
$clent1 = new Customer('client1');
$clent2 = new Customer('client2');
$clent3 = new Customer('client3');
$goods->registerObserver($clent1);
$goods->registerObserver($clent2);
$goods->setEvent('event1');
При изменении состояния объекта $goods методом $goods->setEvent() будут оповещены все клиенты, которые зарегистрировались на отслеживание товара . В нашем случае это клиенты $clent1 и $clent2.
Итоги
Итак, мы рассмотрели шаблон проектирования Observer, который позволяет при изменении состояния одного объекта оповещать заинтересованные в этом компоненты приложения. С его помощью организуется взаимодействие типа «один ко многим», позволяет избежать жесткой зависимости между взаимодействующими объектами.
Перейти к списку шаблонов проектирования.
