Menu
Coddy logo textTech

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.

challenge icon

Aufgabe

Einfach

Lassen 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 eine ConfigLoader-Klasse, die das asynchrone Laden von Konfigurationseinstellungen simuliert. Ihre Klasse sollte Folgendes enthalten:
    • Drei finale Felder: appName (String), version (String) und maxUsers (int)
    • Einen privaten Konstruktor, der alle drei Felder initialisiert
    • Eine statische asynchrone Factory-Methode namens load, die einen String configId-Parameter entgegennimmt und ein Future<ConfigLoader> zurückgibt. Diese Methode sollte:
      • Future.delayed() mit 100 Millisekunden verwenden, um die Ladezeit zu simulieren
      • Die Konfigurationswerte basierend auf der configId generieren:
        • appName: die configId mit angehängtem " App"
        • version: "1.0." gefolgt von der Länge der configId
        • maxUsers: 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)
  • 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 deren displayInfo() auf
    • Laden Sie eine Konfiguration mit der configId "Dev" und rufen Sie deren displayInfo() auf
    • Geben Sie All configs loaded! aus

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
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung