Observer
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 92 di 110.
Il pattern Observer stabilisce una relazione uno-a-molti tra gli oggetti: quando un oggetto (il soggetto) cambia stato, tutti i suoi dipendenti (osservatori) vengono avvisati automaticamente. È perfetto per scenari come gli aggiornamenti dell'interfaccia utente, i sistemi di eventi o qualsiasi situazione in cui più parti della tua applicazione devono reagire ai cambiamenti.
Lo schema coinvolge due ruoli chiave: un soggetto che mantiene un elenco di osservatori e li informa dei cambiamenti, e degli osservatori che si registrano e reagiscono agli aggiornamenti:
abstract class Observer {
void update(String message);
}
class NewsAgency {
final List<Observer> _observers = [];
String _latestNews = '';
void subscribe(Observer observer) {
_observers.add(observer);
}
void unsubscribe(Observer observer) {
_observers.remove(observer);
}
void publishNews(String news) {
_latestNews = news;
for (var observer in _observers) {
observer.update(_latestNews);
}
}
}
class NewsChannel implements Observer {
final String name;
NewsChannel(this.name);
@override
void update(String message) {
print('$name received: $message');
}
}
void main() {
var agency = NewsAgency();
var cnn = NewsChannel('CNN');
var bbc = NewsChannel('BBC');
agency.subscribe(cnn);
agency.subscribe(bbc);
agency.publishNews('Breaking news!');
// CNN received: Breaking news!
// BBC received: Breaking news!
}Quando viene chiamato publishNews, l'agenzia scorre tutti gli osservatori iscritti e chiama il loro metodo update. Gli osservatori possono iscriversi o annullare l'iscrizione in qualsiasi momento, rendendo il sistema flessibile e debolmente accoppiato: il soggetto non deve conoscere i tipi specifici dei suoi osservatori.
Sfida
FacileCostruiamo un sistema di avvisi sui prezzi delle azioni usando il pattern Observer! Creerai un sistema in cui un ticker azionario avvisa più investitori ogni volta che il prezzo cambia, consentendo a ciascun investitore di reagire agli aggiornamenti di mercato a modo suo.
Organizzerai il codice in due file:
stock_system.dart: crea qui il tuo sistema di observer:- Una classe astratta
Investorcon un metodovoid onPriceChange(String stockName, double price) - Una classe
DayTraderche implementaInvestor. Ha un camponamee il suo metodoonPriceChangestampa:[name] sees [stockName] at $[price] - Making quick trade! - Una classe
LongTermInvestorche implementaInvestor. Ha un camponamee il suo metodoonPriceChangestampa:[name] notes [stockName] at $[price] - Holding steady. - Una classe
StockTicker(il soggetto) con:- Un campo
String stockName - Una lista privata in cui memorizzare gli investitori iscritti
- Un metodo
subscribe(Investor investor)per aggiungere un investitore - Un metodo
unsubscribe(Investor investor)per rimuovere un investitore - Un metodo
updatePrice(double newPrice)che notifica tutti gli investitori iscritti del nuovo prezzo
- Un campo
- Una classe astratta
main.dart: importa il tuo sistema azionario e mostra il pattern Observer in azione:- Crea un
StockTickerper un'azione chiamataDART - Crea un
DayTraderchiamatoAlicee unLongTermInvestorchiamatoBob - Iscrivi entrambi gli investitori al ticker
- Aggiorna il prezzo a
150.50(entrambi gli investitori dovrebbero ricevere una notifica) - Stampa una riga vuota
- Annulla l'iscrizione di Alice al ticker
- Aggiorna il prezzo a
155.75(ora solo Bob dovrebbe ricevere una notifica)
- Crea un
Questo dimostra come il pattern Observer crei un sistema debolmente accoppiato: StockTicker non deve sapere se sta notificando day trader o investitori a lungo termine, ma si limita a chiamare onPriceChange su chiunque sia iscritto!
Output previsto:
Alice sees DART at $150.5 - Making quick trade!
Bob notes DART at $150.5 - Holding steady.
Bob notes DART at $155.75 - Holding steady.Provalo tu
import 'stock_system.dart';
void main() {
// TODO: Crea uno StockTicker per un titolo chiamato 'DART'
// TODO: Crea un DayTrader chiamato 'Alice'
// TODO: Crea un LongTermInvestor chiamato 'Bob'
// TODO: Iscrivi entrambi gli investitori al ticker
// TODO: Aggiorna il prezzo a 150.50 (entrambi gli investitori devono ricevere una notifica)
// TODO: Stampa una riga vuota
// TODO: Annulla l'iscrizione di Alice al ticker
// TODO: Aggiorna il prezzo a 155.75 (ora solo Bob deve ricevere una notifica)
}
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 orientata agli oggetti
File esterniLibrerie e importazioniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave thisMetodiVariabili di istanzaFondamenti dei costruttoriRiepilogo - Calcolatrice semplice4Sicurezza dei valori null
Introduzione alla sicurezza dei valori nullNullable e non nullableGli operatori ? e !La keyword late e la sicurezza dei valori nullOperatori null-awareSicurezza dei valori null nelle classiRiepilogo - Sistema di profili utente7Classi astratte e interfacce
Classi astratteMetodi astrattiInterfacce in DartInterfacce impliciteImplementare vs estendereInterfacce multipleRiepilogo - Calcolatore di forme10Collezioni e generici
Panoramica di List, Set e MapCollezioni sicure rispetto ai tipiClassi genericheMetodi genericiVincoli sui genericiIterable e IteratorRiepilogo - Archiviazione generica13Concetti avanzati di OOP
Composizione vs ereditarietàMetodi di estensioneClassi chiamabiliClassi sealed (Dart 3)Record (Dart 3)Pattern e matching (3.0)Enum con metodi16Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente2I costruttori in Dart
Costruttore predefinitoCostruttori con nomeListe di inizializzazioneCostruttori costantiCostruttori factoryCostruttori di reindirizzamentoRiepilogo - Crea forme5Incapsulamento
Membri pubblici e privatiConvenzione del prefisso _Visibilità a livello di libreriaApprofondimento su getter e setterNascondimento delle informazioniRiepilogo - Registri degli studenti8Mixin
Introduzione ai MixinCreare MixinUsare più MixinParola chiave on nei MixinMixin vs ereditarietàMixin vs interfacciaRiepilogo - Sistema animale11Metodi speciali
Sovrascrittura di toString()Sovrascrittura di hashCode e ==Interfaccia ComparableMetodo call()Sovrascrittura di noSuchMethodRiepilogo - Collezione personalizzata14Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneSingletonFactoryObserverStrategy3Proprietà delle classi
Membri di istanza e staticiCampi final e constVariabili lateMetodi e campi staticiGetter e setterRiepilogo - Gestore di conti bancari6Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiL’annotazione @overrideLa parola chiave final per le classiCostruttori ed ereditarietàRiepilogo - Gerarchia dei dipendenti9Polimorfismo
Fondamenti di polimorfismoPolimorfismo tramite interfacceControllo del tipo a runtimeGli operatori is e asParola chiave covariantRiepilogo - Elaboratore di pagamenti12OOP asincrona
Future e async/awaitNozioni di base sugli streamController degli streamCostruttori asincroniAsync nei metodi di classeRiepilogo - Recupero dei dati15Pattern di progettazione Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern RepositoryEsercitati da solo: Compilatore Dart online