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

Как реализовать Observer?

1.7 Middle🔥 171 комментариев
#SOLID и паттерны проектирования

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

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

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

# Паттерн Observer в Java

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

Основные компоненты

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

Реализация с нуля

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

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

// 3. Конкретные реализации Observer
public class ConcreteObserverA implements Observer {
    @Override
    public void update(String event) {
        System.out.println("Observer A received: " + event);
    }
}

public class ConcreteObserverB implements Observer {
    @Override
    public void update(String event) {
        System.out.println("Observer B received: " + event);
    }
}

// 4. Использование
public class Main {
    public static void main(String[] args) {
        Subject subject = new Subject();
        
        Observer observerA = new ConcreteObserverA();
        Observer observerB = new ConcreteObserverB();
        
        subject.attach(observerA);
        subject.attach(observerB);
        
        subject.setState("ACTIVE");
        // Вывод:
        // Observer A received: State changed to: ACTIVE
        // Observer B received: State changed to: ACTIVE
        
        subject.detach(observerA);
        subject.setState("INACTIVE");
        // Вывод:
        // Observer B received: State changed to: INACTIVE
    }
}

Использование встроенного Observer в Java

Java имеет встроенные классы в пакете java.util:

import java.util.Observable;
import java.util.Observer;

// Устаревшая, но всё ещё используемая реализация
public class DataModel extends Observable {
    private String data;
    
    public void setData(String data) {
        this.data = data;
        setChanged();  // Отметить, что состояние изменилось
        notifyObservers(data);  // Уведомить всех наблюдателей
    }
    
    public String getData() {
        return data;
    }
}

public class DisplayObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Data updated: " + arg);
    }
}

// Использование
public class Main {
    public static void main(String[] args) {
        DataModel model = new DataModel();
        DisplayObserver observer = new DisplayObserver();
        
        model.addObserver(observer);
        model.setData("New Value");
    }
}

Современный подход с обобщениями

// Обобщённый Subject
public class EventPublisher<T> {
    private List<EventListener<T>> listeners = new CopyOnWriteArrayList<>();
    
    public void subscribe(EventListener<T> listener) {
        listeners.add(listener);
    }
    
    public void unsubscribe(EventListener<T> listener) {
        listeners.remove(listener);
    }
    
    public void publish(T event) {
        for (EventListener<T> listener : listeners) {
            listener.onEvent(event);
        }
    }
}

public interface EventListener<T> {
    void onEvent(T event);
}

// Пример использования
public class UserEvent {
    private String username;
    private String action;
    
    public UserEvent(String username, String action) {
        this.username = username;
        this.action = action;
    }
    
    public String getUsername() { return username; }
    public String getAction() { return action; }
}

public class LogListener implements EventListener<UserEvent> {
    @Override
    public void onEvent(UserEvent event) {
        System.out.println("Log: User " + event.getUsername() + " performed " + event.getAction());
    }
}

// Использование
EventPublisher<UserEvent> publisher = new EventPublisher<>();
publisher.subscribe(new LogListener());
publisher.publish(new UserEvent("john", "login"));

Практические применения

  1. MVC архитектура — Model уведомляет View об изменениях
  2. Event-driven системы — обработка событий
  3. Reactive программирование — RxJava, Project Reactor
  4. GUI фреймворки — слушатели событий в Swing/JavaFX
  5. Message brokers — Apache Kafka, RabbitMQ

Преимущества и недостатки

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

✅ Слабая связанность между компонентами ✅ Динамическое управление зависимостями ✅ Поддержка broadcast коммуникации

Недостатки

❌ Сложность отладки (трудно отследить событие) ❌ Возможность memory leaks (если забыть отписаться) ❌ Порядок уведомлений непредсказуем ❌ Производительность при большом числе наблюдателей

Рекомендации

  • Используй CopyOnWriteArrayList для потокобезопасности
  • Всегда отписывай наблюдателей когда они больше не нужны
  • Избегай циклических зависимостей
  • Для сложных случаев рассмотри реактивные библиотеки (RxJava)
Как реализовать Observer? | PrepBro