Asynchrone Konstruktoren
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 79 von 110.
Konstruktoren in Dart können nicht als async markiert werden – sie müssen sofort eine Instanz der Klasse zurückgeben, kein Future. Wie erstellt man also Objekte, die eine asynchrone Initialisierung erfordern, wie das Laden von Daten aus einer Datenbank oder das Abrufen von Konfigurationen?
Die Lösung besteht darin, eine statische asynchrone Factory-Methode zu verwenden. Halten Sie den Konstruktor privat (oder einfach) und stellen Sie eine statische Methode bereit, die die asynchrone Arbeit ausführt und ein Future Ihrer Klasse zurückgibt:
class UserProfile {
final String name;
final int age;
UserProfile._(this.name, this.age); // Privater Konstruktor
static Future<UserProfile> create(String userId) async {
// Simuliere das Abrufen von Daten
await Future.delayed(Duration(seconds: 1));
return UserProfile._('Alice', 25);
}
}
Future<void> main() async {
var user = await UserProfile.create('123');
print(user.name); // Alice
}Der private Konstruktor UserProfile._ übernimmt die eigentliche Objekterstellung, während die statische create() Methode die gesamte asynchrone Arbeit erledigt. Aufrufer verwenden await, um das vollständig initialisierte Objekt zu erhalten.
Dieses Muster stellt sicher, dass Ihr Objekt vollständig einsatzbereit ist, sobald Sie es erhalten – keine teilweise initialisierten Zustände oder fehlenden Daten. Es wird häufig für Klassen verwendet, die Ressourcen laden, Verbindungen zu Diensten herstellen oder eine Einrichtung durchführen müssen, die Zeit in Anspruch nimmt.
Aufgabe
EinfachLassen Sie uns einen Konfigurationslader erstellen, der zeigt, wie man mit asynchroner Initialisierung in Klassen umgeht! Da Konstruktoren nicht asynchron sein können, verwenden Sie das statische Factory-Methoden-Muster, um Objekte zu erstellen, die Zeit zum "Laden" ihrer Daten benötigen.
Sie werden Ihren Code in zwei Dateien organisieren:
config_loader.dart: Erstellen Sie eineConfigLoader-Klasse, die das asynchrone Laden von Konfigurationseinstellungen simuliert. Ihre Klasse sollte Folgendes enthalten:- Drei finale Felder:
appName(String),version(String) undmaxUsers(int) - Einen privaten Konstruktor, der alle drei Felder initialisiert
- Eine statische asynchrone Factory-Methode namens
load, die einenString configId-Parameter entgegennimmt und einFuture<ConfigLoader>zurückgibt. Diese Methode sollte:Future.delayed()mit 100 Millisekunden verwenden, um die Ladezeit zu simulieren- Die Konfigurationswerte basierend auf der
configIdgenerieren:appName: die configId mit angehängtem" App"version:"1.0."gefolgt von der Länge der configIdmaxUsers: die Länge der configId multipliziert mit 10
- Eine neue
ConfigLoader-Instanz mit diesen Werten zurückgeben
- Eine
displayInfo()-Methode, welche die Konfiguration in diesem Format ausgibt:Config: [appName] v[version] (max [maxUsers] users)
- Drei finale Felder:
main.dart: Importieren Sie Ihren Konfigurationslader und demonstrieren Sie das asynchrone Initialisierungsmuster:- Geben Sie
Loading configurations...aus - Laden Sie eine Konfiguration mit der configId
"Production"und rufen Sie derendisplayInfo()auf - Laden Sie eine Konfiguration mit der configId
"Dev"und rufen Sie derendisplayInfo()auf - Geben Sie
All configs loaded!aus
- Geben Sie
Beachten Sie, wie die statische load-Methode die gesamte asynchrone Arbeit übernimmt, während der private Konstruktor einfach die Werte zuweist. Aufrufer verwenden await, um ein vollständig initialisiertes Objekt zu erhalten!
Erwartete Ausgabe:
Loading configurations...
Config: Production App v1.0.10 (max 100 users)
Config: Dev App v1.0.3 (max 30 users)
All configs loaded!Spickzettel
Konstruktoren in Dart können nicht als async markiert werden, da sie sofort eine Instanz der Klasse zurückgeben müssen und kein Future.
Um Objekte zu erstellen, die eine asynchrone Initialisierung benötigen, verwenden Sie eine statische asynchrone Factory-Methode:
class UserProfile {
final String name;
final int age;
UserProfile._(this.name, this.age); // Private constructor
static Future<UserProfile> create(String userId) async {
// Perform async work here
await Future.delayed(Duration(seconds: 1));
return UserProfile._('Alice', 25);
}
}Verwendung:
Future<void> main() async {
var user = await UserProfile.create('123');
print(user.name); // Alice
}Der private Konstruktor (markiert mit _) übernimmt die Objekterstellung, während die statische Methode die asynchrone Arbeit erledigt. Dies stellt sicher, dass Objekte vor der Verwendung vollständig initialisiert sind.
Probier es selbst
import 'config_loader.dart';
void main() async {
// TODO: Gebe "Loading configurations..." aus
// TODO: Lade eine Konfiguration mit configId "Production"
// und rufe deren displayInfo() Methode auf
// TODO: Lade eine Konfiguration mit configId "Dev"
// und rufe deren displayInfo() Methode auf
// TODO: Gebe "All configs loaded!" aus
}
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 Processor12Asynchrone OOP
Futures & async/awaitStreams GrundlagenStream ControllerAsynchrone KonstruktorenAsync in KlassenmethodenZusammenfassung – Data Fetcher