Observer (Наблюдатель)
Шаблон проектирования "Наблюдатель" (Observer) используется для создания системы, в которой один объект (называемый "субъектом" или "издателем") уведомляет другие объекты (называемые "наблюдателями") об изменениях своего состояния. Это позволяет реализовать механизм подписки и уведомления, что особенно полезно в ситуациях, когда несколько объектов должны реагировать на изменения состояния другого объекта.
Пример использования паттерна Observer на Java
Рассмотрим пример, в котором у нас есть система погоды. У нас будет класс WeatherData
, который будет представлять данные о погоде, и несколько наблюдателей, которые будут получать обновления о погоде.
Шаг 1: Создание интерфейса наблюдателя
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
Шаг 2: Создание интерфейса субъекта
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
Шаг 3: Реализация класса субъекта
import java.util.ArrayList;
import java.util.List;
public class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
// Метод для обновления данных о погоде
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
notifyObservers(); // Уведомляем наблюдателей об изменении
}
}
Шаг 4: Реализация конкретных наблюдателей
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "°C and " + humidity + "% humidity");
}
}
public class StatisticsDisplay implements Observer {
private float maxTemperature;
private float minTemperature;
private float temperatureSum;
private int numReadings;
@Override
public void update(float temperature, float humidity, float pressure) {
temperatureSum += temperature;
numReadings++;
if (temperature > maxTemperature) {
maxTemperature = temperature;
}
if (temperature < minTemperature || numReadings == 1) {
minTemperature = temperature;
}
display();
}
public void display() {
System.out.println("Avg/Max/Min temperature: " + (temperatureSum / numReadings) + "/" + maxTemperature + "/" + minTemperature);
}
}
Шаг 5: Использование паттерна Observer
Теперь мы можем использовать наш паттерн в коде:
public class ObserverPatternDemo {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
weatherData.registerObserver(currentDisplay);
weatherData.registerObserver(statisticsDisplay);
// Обновляем данные о погоде
weatherData.setMeasurements(25.0f, 65.0f, 1013.0f);
weatherData.setMeasurements(30.0f, 70.0f, 1012.0f);
weatherData.setMeasurements(28.0f, 90.0f, 1011.0f);
}
}
Объяснение
-
Интерфейс
Observer
: Определяет методupdate()
, который будет вызываться для обновления состояния наблюдателя. -
Интерфейс
Subject
: Определяет методы для регистрации, удаления и уведомления наблюдателей. -
Класс
WeatherData
: Реализует интерфейсSubject
. Он хранит список наблюдателей и уведомляет их об изменениях состояния (например, при обновлении данных о погоде). -
Классы
CurrentConditionsDisplay
иStatisticsDisplay
: Реализуют интерфейсObserver
. Они обновляют свое состояние