Pattern Observer
Fa parte della sezione Programmazione orientata agli oggetti del percorso Java di Coddy. Lezione 68 di 87.
Il Pattern Observer è un pattern comportamentale che stabilisce una relazione uno-a-molti tra oggetti. Quando un oggetto (il soggetto) cambia stato, tutti i suoi dipendenti (gli osservatori) vengono automaticamente avvisati e aggiornati. Pensalo come a un abbonamento a una newsletter: gli iscritti ricevono aggiornamenti ogni volta che viene pubblicato un nuovo contenuto.
Il pattern coinvolge due componenti principali: un soggetto che mantiene un elenco di osservatori e li informa delle modifiche, e osservatori che definiscono un metodo di aggiornamento per rispondere alle notifiche:
import java.util.ArrayList;
import java.util.List;
interface Observer {
void update(String message);
}
class NewsPublisher {
private List<Observer> subscribers = new ArrayList<>();
public void subscribe(Observer observer) {
subscribers.add(observer);
}
public void unsubscribe(Observer observer) {
subscribers.remove(observer);
}
public void publish(String news) {
for (Observer subscriber : subscribers) {
subscriber.update(news);
}
}
}
class EmailSubscriber implements Observer {
private String email;
public EmailSubscriber(String email) {
this.email = email;
}
public void update(String message) {
System.out.println("Email to " + email + ": " + message);
}
}Quando l’editore pubblica una notizia, tutti gli iscritti vengono avvisati automaticamente:
NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));
publisher.publish("Breaking news!");
// Output:
// Email a alice@mail.com: Ultime notizie!
// Email a bob@mail.com: Ultime notizie!Il Pattern Observer promuove un accoppiamento debole: il soggetto non deve conoscere le classi concrete dei suoi osservatori, ma solo sapere che implementano l’interfaccia Observer. Questo rende facile aggiungere nuovi tipi di osservatori senza modificare il soggetto.
Sfida
FacileCostruiamo un sistema di avvisi sui prezzi delle azioni usando il pattern Observer! Creerai un sistema in cui un ticker azionario notifica più investitori ogni volta che il prezzo di un'azione cambia, consentendo a ciascun investitore di reagire agli aggiornamenti dei prezzi a modo suo.
Organizzerai il codice in quattro file:
Observer.java: Definisci l'interfacciaObserverche tutti gli investitori implementeranno. Dovrebbe dichiarare un unico metodoupdate(String stockName, double price)che gli osservatori usano per ricevere notifiche sulle variazioni di prezzo.StockTicker.java: Crea la classe soggetto che mantiene un elenco di osservatori e li notifica delle variazioni di prezzo. Il tuoStockTickerdovrebbe avere:Un campo String privato per il nome dell'azione (impostato tramite il costruttore).
Un campo double privato per il prezzo corrente (inizialmente 0).
Un elenco privato per memorizzare gli osservatori iscritti.
Un metodo
subscribe(Observer observer)che aggiunge un osservatore all'elenco.Un metodo
unsubscribe(Observer observer)che rimuove un osservatore dall'elenco.Un metodo
setPrice(double price)che aggiorna il prezzo e poi notifica tutti gli osservatori chiamando il loro metodoupdatecon il nome dell'azione e il nuovo prezzo.Investors.java: Crea due diversi tipi di investitori che implementano l'interfacciaObserver:DayTrader- ha un campo name privato impostato tramite il costruttore. Quando riceve un aggiornamento, stampa[name] received alert: [stockName] is now $[price] - Making quick trade!LongTermInvestor- ha un campo name privato impostato tramite il costruttore. Quando riceve un aggiornamento, stampa[name] received alert: [stockName] is now $[price] - Holding steady.Formatta il prezzo con due cifre decimali.
Main.java: Metti insieme il tuo sistema di osservatori! Riceverai tre input: il nome dell'azione (String), il primo aggiornamento del prezzo (double) e il secondo aggiornamento del prezzo (double).Crea uno
StockTickercon il nome dell'azione fornito. Crea unDayTraderchiamato"Alice"e unLongTermInvestorchiamato"Bob", quindi iscrivi entrambi al ticker.Imposta il prezzo sul valore del primo input (tutti gli osservatori ricevono una notifica). Poi annulla l'iscrizione di Alice. Infine, imposta il prezzo sul valore del secondo input (questa volta dovrebbe ricevere una notifica solo Bob).
Riceverai tre input in questo ordine: nome dell'azione (String), primo prezzo (double), secondo prezzo (double).
Questa sfida dimostra la potenza del pattern Observer: StockTicker non sa nulla dei tipi specifici di investitore. Sa solo che implementano Observer. Quando annulli l'iscrizione di Alice, lei smette di ricevere aggiornamenti mentre Bob continua a essere avvisato. Questo accoppiamento debole rende facile aggiungere nuovi tipi di investitore senza modificare il ticker!
Provalo tu
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Leggi i dati di input
String stockName = scanner.nextLine();
double firstPrice = scanner.nextDouble();
double secondPrice = scanner.nextDouble();
// TODO: Crea un StockTicker con il nome del titolo fornito
// TODO: Crea un DayTrader chiamato "Alice"
// TODO: Crea un LongTermInvestor chiamato "Bob"
// TODO: Iscrivi sia Alice sia Bob al ticker
// TODO: Imposta il prezzo su firstPrice (entrambi gli osservatori ricevono una notifica)
// TODO: Annulla l'iscrizione di Alice
// TODO: Imposta il prezzo su secondPrice (solo Bob riceve una notifica)
scanner.close();
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione a oggetti
File esterniIntroduzione alla programmazione a oggettiClassi e oggettiLa parola chiave thisMetodiCampi (attributi)Metodo costruttoreSovraccarico dei costruttoriRipasso - Calcolatrice semplice4Ereditarietà
Ereditarietà di base (extends)La parola chiave superSovrascrittura dei metodi (@Override)Concatenamento dei costruttoriLa classe ObjectEreditarietà singola e multilivelloPerché non esiste l'ereditarietà multipla delle classiRiepilogo: gerarchia dei dipendenti7Metodi speciali e classe Object
Metodo toString()equals() e hashCode()Metodo clone()compareTo() e ComparableInterfaccia ComparatorRiepilogo - Ordinamento personalizzato2Modificatori di accesso e incapsulamento
Panoramica dei livelli di accessoMetodi getter e setterNascondimento delle informazioniLa parola chiave finalRiepilogo - Gestore di conti bancari5Polimorfismo
Nozioni di base sull'overloading dei metodiOverride dei metodi (a runtime)Upcasting e downcastingL'operatore instanceofClassi e metodi astrattiRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàAggregazione vs composizioneClassi interne, annidate e anonimeEnum e metodi degli EnumRecord (Java 16+)Classi sealed (Java 17+)11Modelli di progettazione Parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern BuilderPattern ObserverPattern Strategy3Proprietà di classe e membri statici
Variabili di istanza e staticheMetodi staticiBlocchi staticiCostanti (static final)Riepilogo - Contatore e utility6Interfacce e classi astratte
Introduzione alle interfacceImplementazione delle interfacceImplementazione di più interfacceMetodi default e static nelle interfacceClassi astratte e interfacce a confrontoInterfacce funzionaliRiepilogo: sistema di pagamento9Tipi generici
Introduzione ai tipi genericiClassi genericheMetodi genericiParametri di tipo con limitiCaratteri jolly (?, extends, super)Riepilogo - Contenitore generico12Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern IteratorEsercitati da solo: Compilatore Java online