Шаблон проектирования Observer

Шаблон проектирования Observer относится к поведенческим паттернам и предназначен для реализации механизма подписки объектов друг на друга. Основная идея заключается в том, что один объект («наблюдатель») подписывается на изменения состояния другого объекта («субъекта»), чтобы получать уведомления о произошедших изменениях и реагировать соответствующим образом.

Основные элементы шаблона Observer

Субъект (Subject)

Объект, состояние которого отслеживается наблюдателями. Его основные обязанности:

  • Регистрация новых подписчиков (наблюдателей).
  • Удаление подписчиков.
  • Уведомление всех зарегистрированных наблюдателей о наступлении события или изменении своего состояния.

Наблюдатели (Observers)

Наблюдатели — объекты, интересующиеся изменениями состояния субъекта. Их задача — обрабатывать уведомление, отправленное субъектом, и предпринимать необходимые действия.


Пример реализации на PHP

Представим ситуацию, когда нам нужно создать простую систему уведомлений пользователей сайта о поступивших комментариях на посты.

<?php

// Интерфейс Subject
interface Subject {
    public function attach($observer);
    public function detach($observer);
    public function notify();
}

// Реализация Subject
class Post implements Subject {
    private array $observers = [];
    private string $title;
    private int $commentsCount = 0;
    
    // Конструктор поста
    public function __construct(string $title)
    {
        $this->title = $title;
    }

    // Добавляем нового наблюдателя
    public function attach($observer): void
    {
        if (!in_array($observer, $this->observers)) {
            $this->observers[] = $observer;
        }
    }

    // Отписываем наблюдателя
    public function detach($observer): void
    {
        foreach ($this->observers as $key => $value) {
            if ($value === $observer) {
                unset($this->observers[$key]);
            }
        }
    }

    // Оповещаем всех наблюдателей
    public function notify(): void
    {
        foreach ($this->observers as $observer) {
            $observer->update($this); // Передаем ссылку на себя
        }
    }

    // Метод обновления комментариев
    public function addComment()
    {
        $this->commentsCount++;
        echo 'Новый комментарий! Общее количество: ' . $this->commentsCount . "\n";
        $this->notify(); // После добавления комментария оповещаем всех наблюдателей
    }

    // Получаем название поста
    public function getTitle(): string
    {
        return $this->title;
    }

    // Получаем количество комментариев
    public function getCommentsCount(): int
    {
        return $this->commentsCount;
    }
}

// Интерфейс Observer
interface Observer {
    public function update(Subject $subject);
}

// Реализация конкретного наблюдателя (например, Email-подписчик)
class UserEmail implements Observer {
    private string $email;

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

    // Метод обработки изменений
    public function update(Subject $subject): void
    {
        echo 'Отправлено письмо на адрес ' . $this->email .
             ': Пост "' . $subject->getTitle() . '" получил новый комментарий!' . "\n";
    }
}

// Создаем пост
$post = new Post('Обзор iPhone 15');

// Подписчики
$user1 = new UserEmail('ivan@example.com');
$user2 = new UserEmail('mariia@example.com');

// Регистрируем наблюдателей
$post->attach($user1);
$post->attach($user2);

// Моделируем действие комментирования
for ($i = 0; $i < 3; $i++) {
    $post->addComment();
}

Как работает этот пример?

  1. Мы создаем класс Post, который реализует интерфейс Subject. Этот класс управляет списком подписчиков и вызывает метод notify() всякий раз, когда добавляется новый комментарий.
  2. Затем мы определяем наблюдателей, реализуя интерфейс Observer в классе UserEmail. Каждый экземпляр класса представляет собой одного подписчика, ожидающего уведомлений о появлении новых комментариев.
  3. Когда происходит событие (добавляется комментарий), каждый зарегистрированный наблюдатель получает уведомление и выполняет своё действие (отправляет email-сообщение).

Преимущества шаблона Observer:

  • Позволяет реализовать гибкую связь между объектами, не связывая их жестко друг с другом.
  • Удобство масштабируемости системы благодаря возможности легко добавлять/удалять новые типы наблюдателей.
  • Улучшение производительности путем ограничения операций обновлений лишь теми объектами, которым действительно нужны уведомления.

Таким образом, шаблон Observer является полезным инструментом для разработки веб-приложений на PHP, особенно там, где необходима динамическая реакция компонентов на изменение состояния других элементов приложения.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *