| title | Observer | ||
|---|---|---|---|
| category | Behavioral | ||
| language | it | ||
| tag |
|
Dependents, Publish-Subscribe
Stabilire una dipendenza uno-a-molti tra gli oggetti in modo che quando un oggetto cambia stato, tutti i suoi dipendenti vengano avvisati e aggiornati automaticamente.
Esempio del mondo reale
In una terra lontana vivono le razze degli hobbit e degli orchi. Entrambi trascorrono la maggior parte del tempo all'aperto, quindi seguono attentamente i cambiamenti del tempo. Si potrebbe dire che osservano costantemente le condizioni meteorologiche.
In parole semplici
Registrarsi come osservatore per ricevere notifiche di cambiamenti di stato nell'oggetto.
Wikipedia dice
Il pattern observer è un design pattern in cui un oggetto, chiamato soggetto, mantiene una lista dei suoi dipendenti, chiamati osservatori, e li avvisa automaticamente di eventuali cambiamenti di stato, di solito chiamando uno dei loro metodi. (Testo tradotto dalla voce Observer Pattern da Wikipedia in lingua inglese).
Esempio di codice
Iniziamo introducendo l'interfaccia WeatherObserver e le nostre razze, Orcs e Hobbits.
public interface WeatherObserver {
void update(WeatherType currentWeather);
}
@Slf4j
public class Orcs implements WeatherObserver {
@Override
public void update(WeatherType currentWeather) {
LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now");
}
}
@Slf4j
public class Hobbits implements WeatherObserver {
@Override
public void update(WeatherType currentWeather) {
switch (currentWeather) {
LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
}
}
}Poi c'è il Weather che cambia continuamente.
@Slf4j
public class Weather {
private WeatherType currentWeather;
private final List<WeatherObserver> observers;
public Weather() {
observers = new ArrayList<>();
currentWeather = WeatherType.SUNNY;
}
public void addObserver(WeatherObserver obs) {
observers.add(obs);
}
public void removeObserver(WeatherObserver obs) {
observers.remove(obs);
}
/**
* Makes time pass for weather.
*/
public void timePasses() {
var enumValues = WeatherType.values();
currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
LOGGER.info("The weather changed to {}.", currentWeather);
notifyObservers();
}
private void notifyObservers() {
for (var obs : observers) {
obs.update(currentWeather);
}
}
}Ecco l'esempio completo in azione.
var weather = new Weather();
weather.addObserver(new Orcs());
weather.addObserver(new Hobbits());
weather.timePasses();
weather.timePasses();
weather.timePasses();
weather.timePasses();Output del programma:
The weather changed to rainy.
The orcs are facing rainy weather now
The hobbits are facing rainy weather now
The weather changed to windy.
The orcs are facing windy weather now
The hobbits are facing windy weather now
The weather changed to cold.
The orcs are facing cold weather now
The hobbits are facing cold weather now
The weather changed to sunny.
The orcs are facing sunny weather now
The hobbits are facing sunny weather now
Usa il pattern Observer in una qualsiasi delle seguenti situazioni:
- Quando un'astrazione ha due aspetti, uno dipendente dall'altro. L'incapsulamento di questi aspetti in oggetti separati ti permette di variarli e riutilizzarli in modo indipendente.
- Quando una modifica a un oggetto richiede la modifica di altri oggetti, e non sai quanti oggetti devono essere modificati.
- Quando un oggetto dovrebbe essere in grado di avvisare altri oggetti senza fare presupposizioni su chi siano questi oggetti. In altre parole, non desideri che questi oggetti siano strettamente accoppiati.
