Costruttori asincroni
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 79 di 110.
I costruttori in Dart non possono essere contrassegnati come async: devono restituire immediatamente un'istanza della classe, non un Future. Quindi, come si creano oggetti che richiedono un'inizializzazione asincrona, come il caricamento di dati da un database o il recupero della configurazione?
La soluzione consiste nell'usare un metodo factory statico asincrono. Mantieni il costruttore privato (o semplice) e fornisci un metodo statico che esegua il lavoro asincrono e restituisca un Future della tua classe:
class UserProfile {
final String name;
final int age;
UserProfile._(this.name, this.age); // Costruttore privato
static Future<UserProfile> create(String userId) async {
// Simula il recupero dei dati
await Future.delayed(Duration(seconds: 1));
return UserProfile._('Alice', 25);
}
}
Future<void> main() async {
var user = await UserProfile.create('123');
print(user.name); // Alice
}Il costruttore privato UserProfile._ gestisce la creazione effettiva dell’oggetto, mentre il metodo statico create() gestisce tutto il lavoro asincrono. Chi chiama usa await per ottenere l’oggetto completamente inizializzato.
Questo schema assicura che il tuo oggetto sia completamente pronto all'uso non appena lo ottieni: niente stati inizializzati solo parzialmente né dati mancanti. È comunemente usato per le classi che devono caricare risorse, connettersi a servizi o eseguire operazioni di configurazione che richiedono tempo.
Sfida
FacileCostruiamo un caricatore di configurazione che mostri come gestire l’inizializzazione asincrona nelle classi! Poiché i costruttori non possono essere asincroni, userai il modello del metodo factory statico per creare oggetti che hanno bisogno di tempo per "caricare" i propri dati.
Organizzerai il codice in due file:
config_loader.dart: crea una classeConfigLoaderche simula il caricamento asincrono delle impostazioni di configurazione. La classe dovrebbe avere:- Tre campi final:
appName(String),version(String) emaxUsers(int) - Un costruttore privato che inizializza tutti e tre i campi
- Un metodo factory statico asincrono chiamato
loadche accetta un parametroString configIde restituisce unFuture<ConfigLoader>. Questo metodo dovrebbe:- Usare
Future.delayed()con 100 millisecondi per simulare il tempo di caricamento - Generare i valori di configurazione in base a
configId:appName: configId seguito da" App"version:"1.0."seguito dalla lunghezza di configIdmaxUsers: la lunghezza di configId moltiplicata per 10
- Restituire una nuova istanza di
ConfigLoadercon questi valori
- Usare
- Un metodo
displayInfo()che stampa la configurazione in questo formato:Config: [appName] v[version] (max [maxUsers] users)
- Tre campi final:
main.dart: importa il caricatore di configurazione e mostra il modello di inizializzazione asincrona:- Stampa
Loading configurations... - Carica una configurazione con configId
"Production"e chiama il suo metododisplayInfo() - Carica una configurazione con configId
"Dev"e chiama il suo metododisplayInfo() - Stampa
All configs loaded!
- Stampa
Nota come il metodo statico load gestisce tutto il lavoro asincrono, mentre il costruttore privato si limita ad assegnare i valori. Chi chiama il metodo usa await per ottenere un oggetto completamente inizializzato!
Output previsto:
Loading configurations...
Config: Production App v1.0.10 (max 100 users)
Config: Dev App v1.0.3 (max 30 users)
All configs loaded!Provalo tu
import 'config_loader.dart';
void main() async {
// TODO: Stampa "Loading configurations..."
// TODO: Carica una configurazione con configId "Production"
// e chiama il suo metodo displayInfo()
// TODO: Carica una configurazione con configId "Dev"
// e chiama il suo metodo displayInfo()
// TODO: Stampa "All configs loaded!"
}
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