Observer-Muster
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 92 von 110.
Das Observer-Pattern stellt eine Eins-zu-viele-Beziehung zwischen Objekten her: Wenn ein Objekt (das Subjekt) seinen Zustand ändert, werden alle seine Abhängigen (Beobachter) automatisch benachrichtigt. Dies ist ideal für Szenarien wie UI-Updates, Event-Systeme oder jede Situation, in der mehrere Teile Ihrer Anwendung auf Änderungen reagieren müssen.
Das Muster umfasst zwei Schlüsselrollen: ein Subject, das eine Liste von Objekten führt und sie über Änderungen benachrichtigt, und Observers, die sich selbst registrieren und auf Aktualisierungen reagieren:
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 hat empfangen: Breaking news!
// BBC hat empfangen: Breaking news!
}Wenn publishNews aufgerufen wird, iteriert die Agentur durch alle abonnierten Observer und ruft deren update-Methode auf. Observer können sich jederzeit an- oder abmelden, was das System flexibel und lose gekoppelt macht – das Subjekt muss die spezifischen Typen seiner Observer nicht kennen.
Aufgabe
EinfachLassen Sie uns ein Aktienkurs-Alarmsystem mit dem Observer-Muster bauen! Sie werden ein System erstellen, bei dem ein Stock-Ticker mehrere Investoren benachrichtigt, wann immer sich der Preis ändert, sodass jeder Investor auf seine eigene Weise auf Marktaktualisierungen reagieren kann.
Sie werden Ihren Code in zwei Dateien organisieren:
stock_system.dart: Erstellen Sie hier Ihr Observer-System:- Eine abstrakte Klasse
Investormit einer Methodevoid onPriceChange(String stockName, double price) - Eine Klasse
DayTrader, dieInvestorimplementiert. Sie hat einname-Feld und ihreonPriceChange-Methode gibt aus:[name] sees [stockName] at $[price] - Making quick trade! - Eine Klasse
LongTermInvestor, dieInvestorimplementiert. Sie hat einname-Feld und ihreonPriceChange-Methode gibt aus:[name] notes [stockName] at $[price] - Holding steady. - Eine Klasse
StockTicker(das Subjekt) mit:- Einem
String stockName-Feld - Einer privaten Liste zum Speichern der abonnierten Investoren
- Einer
subscribe(Investor investor)-Methode, um einen Investor hinzuzufügen - Einer
unsubscribe(Investor investor)-Methode, um einen Investor zu entfernen - Einer
updatePrice(double newPrice)-Methode, die alle abonnierten Investoren über den neuen Preis benachrichtigt
- Einem
- Eine abstrakte Klasse
main.dart: Importieren Sie Ihr Aktiensystem und demonstrieren Sie das Observer-Muster in Aktion:- Erstellen Sie einen
StockTickerfür eine Aktie namensDART - Erstellen Sie einen
DayTradernamensAliceund einenLongTermInvestornamensBob - Abonnieren Sie beide Investoren beim Ticker
- Aktualisieren Sie den Preis auf
150.50(beide Investoren sollten benachrichtigt werden) - Geben Sie eine Leerzeile aus
- Melden Sie Alice vom Ticker ab
- Aktualisieren Sie den Preis auf
155.75(jetzt sollte nur noch Bob benachrichtigt werden)
- Erstellen Sie einen
Dies zeigt, wie das Observer-Muster ein lose gekoppeltes System schafft – der StockTicker muss nicht wissen, ob er Daytrader oder langfristige Investoren benachrichtigt, er ruft einfach onPriceChange bei jedem auf, der abonniert ist!
Erwartete Ausgabe:
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.Spickzettel
Das Observer-Muster etabliert eine Eins-zu-viele-Beziehung, bei der ein Subjekt alle seine Beobachter benachrichtigt, wenn sich sein Zustand ändert.
Das Muster hat zwei Schlüsselrollen:
- Subject: Verwaltet eine Liste von Beobachtern und benachrichtigt sie über Änderungen
- Observer: Registriert sich beim Subjekt und reagiert auf Aktualisierungen
Grundlegende Implementierung:
abstract class Observer {
void update(String message);
}
class Subject {
final List<Observer> _observers = [];
void subscribe(Observer observer) {
_observers.add(observer);
}
void unsubscribe(Observer observer) {
_observers.remove(observer);
}
void notifyObservers(String data) {
for (var observer in _observers) {
observer.update(data);
}
}
}
class ConcreteObserver implements Observer {
final String name;
ConcreteObserver(this.name);
@override
void update(String message) {
print('$name received: $message');
}
}Wesentliche Vorteile:
- Lose Kopplung zwischen Subjekt und Beobachtern
- Beobachter können sich dynamisch an- und abmelden (subscribe/unsubscribe)
- Das Subjekt muss die spezifischen Typen der Beobachter nicht kennen
Probier es selbst
import 'stock_system.dart';
void main() {
// TODO: Erstelle einen StockTicker für eine Aktie namens 'DART'
// TODO: Erstelle einen DayTrader namens 'Alice'
// TODO: Erstelle einen LongTermInvestor namens 'Bob'
// TODO: Melde beide Investoren beim ticker an
// TODO: Aktualisiere den Preis auf 150.50 (beide Investoren sollten benachrichtigt werden)
// TODO: Gib eine Leerzeile aus
// TODO: Melde Alice vom ticker ab
// TODO: Aktualisiere den Preis auf 155.75 (jetzt sollte nur Bob benachrichtigt werden)
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor