← Назад к вопросам

Что такое шаблон проектирования Observer?

2.8 Senior🔥 161 комментариев
#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое шаблон проектирования Observer?

Observer — это поведенческий паттерн проектирования, который определяет отношение один-ко-многим между объектами таким образом, что при изменении состояния одного объекта все зависящие от него объекты уведомляются об этом автоматически. Паттерн также известен как Publish-Subscribe или Event-Driven.

Основная идея

Subject (Издатель)  --->  Observer1 (Подписчик)
  |                  \---> Observer2 (Подписчик)
  |                   ---> Observer3 (Подписчик)
  |
  +-- При изменении состояния:
      уведомляет ВСЕ Observer'ы

Участники паттерна

  1. Subject (издатель) — объект, за которым наблюдают
  2. Observer (подписчик) — интерфейс для объектов, которые должны быть уведомлены
  3. ConcreteSubject — конкретная реализация издателя
  4. ConcreteObserver — конкретная реализация подписчика

Классическая реализация Observer

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

// 2. Subject (издатель)
public class Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;
    
    // Подписка на события
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    // Отписка от событий
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    // Уведомление всех наблюдателей
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(this);
        }
    }
    
    // Изменение состояния
    public void setState(String state) {
        this.state = state;
        notifyObservers(); // Автоматически уведомляем
    }
    
    public String getState() {
        return state;
    }
}

// 3. Конкретные Observer'ы
public class ConcreteObserver1 implements Observer {
    private String name = "Observer1";
    
    @Override
    public void update(Subject subject) {
        System.out.println(name + " получил уведомление. Новое состояние: " + 
                         subject.getState());
        reactToUpdate();
    }
    
    private void reactToUpdate() {
        System.out.println(name + " выполняет действие");
    }
}

public class ConcreteObserver2 implements Observer {
    private String name = "Observer2";
    
    @Override
    public void update(Subject subject) {
        if (subject.getState().equals("SpecialState")) {
            System.out.println(name + " реагирует на специальное состояние");
        }
    }
}

// 4. Использование
public class ObserverDemo {
    public static void main(String[] args) {
        Subject subject = new Subject();
        
        // Регистрируем наблюдателей
        Observer observer1 = new ConcreteObserver1();
        Observer observer2 = new ConcreteObserver2();
        
        subject.attach(observer1);
        subject.attach(observer2);
        
        // Изменяем состояние
        subject.setState("NewState");
        // Вывод:
        // Observer1 получил уведомление. Новое состояние: NewState
        // Observer1 выполняет действие
        
        subject.setState("SpecialState");
        // Вывод:
        // Observer1 получил уведомление. Новое состояние: SpecialState
        // Observer1 выполняет действие
        // Observer2 реагирует на специальное состояние
    }
}

Observer в Java: Event-Listener паттерн

Ява имеет встроенную поддержку Observer'а через Event-Listener механизм:

// 1. EventObject (можно расширить)
public class WeatherEvent extends EventObject {
    private String temperature;
    
    public WeatherEvent(Object source, String temperature) {
        super(source);
        this.temperature = temperature;
    }
    
    public String getTemperature() {
        return temperature;
    }
}

// 2. Listener интерфейс
public interface WeatherListener extends EventListener {
    void onWeatherChanged(WeatherEvent event);
}

// 3. Subject (EventSource)
public class WeatherStation {
    private List<WeatherListener> listeners = new ArrayList<>();
    private String temperature;
    
    public void addWeatherListener(WeatherListener listener) {
        listeners.add(listener);
    }
    
    public void removeWeatherListener(WeatherListener listener) {
        listeners.remove(listener);
    }
    
    public void setTemperature(String temp) {
        this.temperature = temp;
        
        // Уведомляем всех слушателей
        for (WeatherListener listener : listeners) {
            listener.onWeatherChanged(new WeatherEvent(this, temp));
        }
    }
}

// 4. Конкретные слушатели
public class TemperatureDisplay implements WeatherListener {
    @Override
    public void onWeatherChanged(WeatherEvent event) {
        System.out.println("Дисплей: текущая температура " + event.getTemperature());
    }
}

public class WeatherAlarm implements WeatherListener {
    @Override
    public void onWeatherChanged(WeatherEvent event) {
        String temp = event.getTemperature();
        if (temp.contains("-30")) {
            System.out.println("ВНИМАНИЕ: Опасно холодная погода!");
        }
    }
}

// 5. Использование
WeatherStation station = new WeatherStation();
station.addWeatherListener(new TemperatureDisplay());
station.addWeatherListener(new WeatherAlarm());

station.setTemperature("25C");
// Дисплей: текущая температура 25C

station.setTemperature("-30C");
// Дисплей: текущая температура -30C
// ВНИМАНИЕ: Опасно холодная погода!

Observer в Spring Framework

Spring предоставляет ApplicationEventPublisher для реализации Observer'а:

// 1. Событие (Event)
public class UserRegisteredEvent extends ApplicationEvent {
    private User user;
    
    public UserRegisteredEvent(Object source, User user) {
        super(source);
        this.user = user;
    }
    
    public User getUser() {
        return user;
    }
}

// 2. Publisher (издатель)
@Service
public class UserService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public void registerUser(User user) {
        // Регистрируем пользователя
        saveUser(user);
        
        // Публикуем событие
        eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
    }
    
    private void saveUser(User user) {
        // Логика сохранения
    }
}

// 3. Observer'ы (слушатели)
@Component
public class EmailNotificationListener {
    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("Отправляем письмо на " + user.getEmail());
        sendWelcomeEmail(user);
    }
    
    private void sendWelcomeEmail(User user) {
        // Логика отправки письма
    }
}

@Component
public class LoggingListener {
    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("Пользователь зарегистрирован: " + user.getUsername());
    }
}

@Component
public class AnalyticsListener {
    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("Отправляем аналитику");
        trackUserRegistration(user);
    }
    
    private void trackUserRegistration(User user) {
        // Логика аналитики
    }
}

Observer с RxJava

RxJava предоставляет реактивный подход к Observer'у через Observable и Observer:

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;

// 1. Observable (издатель)
Observable<String> messageObservable = Observable.create(emitter -> {
    emitter.onNext("First message");
    emitter.onNext("Second message");
    emitter.onNext("Third message");
    emitter.onComplete();
});

// 2. Observer (подписчик)
Observer<String> messageObserver = new Observer<String>() {
    @Override
    public void onSubscribe(Disposable d) {
        System.out.println("Подписка установлена");
    }
    
    @Override
    public void onNext(String message) {
        System.out.println("Получено: " + message);
    }
    
    @Override
    public void onError(Throwable e) {
        System.err.println("Ошибка: " + e.getMessage());
    }
    
    @Override
    public void onComplete() {
        System.out.println("Завершено");
    }
};

// 3. Подписка
messageObservable.subscribe(messageObserver);

// Вывод:
// Подписка установлена
// Получено: First message
// Получено: Second message
// Получено: Third message
// Завершено

Преимущества Observer'а

// 1. Слабая связность
// Subject не знает деталей Observer'ов, только интерфейс

// 2. Динамическая подписка
Observer observer = new ConcreteObserver();
subject.attach(observer);     // Подписка во время выполнения
subject.detach(observer);     // Отписка во время выполнения

// 3. Broadcast communication
// Один subject может уведомлять множество observer'ов

// 4. Соответствует принципу Open/Closed
// Можно добавить новых observer'ов без изменения subject

Недостатки Observer'а

// 1. Порядок вызовов непредсказуем
for (Observer observer : observers) {
    observer.update(this); // Порядок зависит от порядка регистрации
}

// 2. Observer'ы остаются в памяти при утечке ссылок
// ПОМНИ: нужно отписывать!

// 3. Может быть сложным в отладке
// Когда множество observer'ов реагируют на событие

Реальные примеры использования

1. Model-View паттерн (MVC)
   - Model: Subject
   - View: Observer
   - При изменении Model, все View обновляются

2. Event-driven архитектура
   - UI события (button clicks, mouse moves)

3. Pub-Sub системы
   - Kafka, RabbitMQ

4. Real-time updates
   - WebSockets, Server-Sent Events

5. Reactive programming
   - RxJava, Project Reactor

Сравнение с другими паттернами

Observer    - один-ко-многим, уведомления
Mediator    - много-ко-многим, координация
Publisher-Subscriber - асинхронная коммуникация
Mediator   - синхронная координация

Pattern Observer — один из самых широко используемых паттернов в современном ПО, особенно в UI фреймворках, event-driven системах и reactive программировании. Его понимание критически важно для разработчика Java.

Что такое шаблон проектирования Observer? | PrepBro