Как называется паттерн для подписки на событие?

«Как называется паттерн для подписки на событие?» — вопрос из категории Паттерны, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Паттерн называется Наблюдатель (Observer).

Суть паттерна: Определяет зависимость «один-ко-многим» между объектами таким образом, что при изменении состояния одного объекта (Субъекта) все зависящие от него объекты (Наблюдатели) автоматически уведомляются и обновляются.

Классическая реализация на Java:

import java.util.ArrayList;
import java.util.List;

// Интерфейс Наблюдателя
interface Observer {
    void update(String eventData);
}

// Интерфейс Субъекта (Издателя)
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// Конкретный Субъект
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;

    public void setState(String state) {
        this.state = state;
        notifyObservers(); // Уведомляем всех при изменении состояния
    }

    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }
}

// Конкретные Наблюдатели
class LoggerObserver implements Observer {
    @Override
    public void update(String eventData) {
        System.out.println("[Logger] Event received: " + eventData);
    }
}

class NotificationService implements Observer {
    @Override
    public void update(String eventData) {
        System.out.println("[Notification] Sending alert for: " + eventData);
    }
}

// Использование
public class Main {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        subject.attach(new LoggerObserver());
        subject.attach(new NotificationService());

        // Изменение состояния субъекта вызовет уведомление всех наблюдателей
        subject.setState("USER_LOGGED_IN");
        subject.setState("ORDER_CREATED");
    }
}

Где я применял Observer:

  • Система событий в UI-фреймворках: Например, обработка кликов кнопок в Android (OnClickListener) или во фронтенд-фреймворках.
  • Реактивное программирование: Библиотеки вроде RxJava или Project Reactor построены на идеях, схожих с этим паттерном.
  • Логирование и аудит: Подписка сервиса логирования на события бизнес-логики (создание заказа, изменение статуса).
  • Отправка уведомлений: При изменении статуса задачи — уведомление ответственного менеджера по email и в Telegram.

Ключевое преимущество: Субъект и наблюдатели слабо связаны. Субъект ничего не знает о конкретных классах наблюдателей, а только об интерфейсе. Это позволяет легко добавлять новых наблюдателей, не изменяя код субъекта.