Sicurezza dei valori null nelle classi
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 28 di 110.
Quando progetti le classi, devi decidere quali campi sono obbligatori e quali facoltativi. La sicurezza rispetto ai valori null influisce sul modo in cui dichiari le variabili di istanza e scrivi i costruttori.
I campi non nullable devono essere inizializzati prima che venga eseguito il corpo del costruttore. Puoi farlo tramite liste di inizializzazione, parametri del costruttore o valori predefiniti:
class User {
String name; // Deve essere inizializzato
String? bio; // Facoltativo - può essere null
int age = 0; // Ha un valore predefinito
User(this.name); // name viene inizializzato tramite un parametro
}Per i campi nullable, puoi lasciarli non inizializzati, poiché il valore predefinito è null. Questo è utile per i dati facoltativi:
class Product {
String title;
String? description; // Descrizione facoltativa del prodotto
double? discount; // Nessuno sconto per impostazione predefinita
Product(this.title);
}
var item = Product('Laptop');
print(item.description); // null
print(item.discount); // nullQuando accedi ai campi nullable, usa gli operatori null-aware che hai imparato:
class Order {
String id;
User? customer;
Order(this.id);
String getCustomerName() {
return customer?.name ?? 'Guest';
}
}La parola chiave required nei parametri con nome assicura che chi chiama fornisca i valori essenziali:
class Account {
String email;
String? phone;
Account({required this.email, this.phone});
}
var acc = Account(email: 'test@mail.com'); // phone è facoltativoScegliendo con criterio tra campi nullable e non nullable, crei classi che comunicano chiaramente quali dati sono essenziali e quali facoltativi.
Sfida
FacileCreiamo un sistema di prenotazione per un hotel che dimostri come progettare classi con un'attenta combinazione di campi obbligatori e facoltativi usando la sicurezza rispetto ai valori null.
Organizzerai il codice in due file:
reservation.dart: definisci una classeReservationche rappresenta una prenotazione alberghiera. Ogni prenotazione richiede alcune informazioni essenziali, ma alcuni dettagli sono extra facoltativi che gli ospiti possono fornire o meno. La tua classe dovrebbe avere:- Un
String guestNamenon nullable: ogni prenotazione deve avere il nome di un ospite - Un
int roomNumbernon nullable: a ogni prenotazione deve essere assegnata una camera - Un
int nightsnon nullable con valore predefinito1: il soggiorno minimo è di una notte - Un
String? specialRequestsnullable: gli ospiti possono avere richieste speciali - Un
DateTime? checkInTimenullable: l'ora esatta di arrivo potrebbe non essere nota - Un costruttore che usa parametri con nome e
requiredperguestNameeroomNumber, mentrenightsdovrebbe essere facoltativo e avere il suo valore predefinito - Un metodo
getRequestsSummary()che restituisce le richieste speciali, se specificate, oppure'No special requests'usando l'operatore?? - Un metodo
getArrivalInfo()che restituisce la rappresentazione in stringa dell'ora di check-in usando?., oppurenullse non è impostata - Un metodo
printConfirmation()che visualizza i dettagli della prenotazione
- Un
main.dart: importa la classe della prenotazione e crea prenotazioni che mostrino diverse combinazioni di dati obbligatori e facoltativi:- Crea una prenotazione per l'ospite
'Sarah Johnson'nella camera101per3notti, con richieste speciali'Late checkout'e ora di check-in impostata suDateTime(2024, 6, 15, 14, 30) - Crea una prenotazione per l'ospite
'Mike Chen'nella camera205(usa il numero predefinito di notti), impostando solo le richieste speciali su'Extra pillows' - Crea una prenotazione per l'ospite
'Emma Davis'nella camera310per2notti (lascia entrambi i campi facoltativi impostati su null) - Per ogni prenotazione, nell'ordine, chiama
printConfirmation(), poi stampaArrival: [result]usandogetArrivalInfo()
- Crea una prenotazione per l'ospite
Il metodo printConfirmation() dovrebbe stampare in questo formato:
=== Reservation Confirmed ===
Guest: [guestName]
Room: [roomNumber]
Nights: [nights]
Requests: [getRequestsSummary()]Output previsto:
=== Reservation Confirmed ===
Guest: Sarah Johnson
Room: 101
Nights: 3
Requests: Late checkout
Arrival: 2024-06-15 14:30:00.000
=== Reservation Confirmed ===
Guest: Mike Chen
Room: 205
Nights: 1
Requests: Extra pillows
Arrival: null
=== Reservation Confirmed ===
Guest: Emma Davis
Room: 310
Nights: 2
Requests: No special requests
Arrival: nullProvalo tu
import 'reservation.dart';
void main() {
// TODO: Crea una prenotazione per 'Sarah Johnson'
// Camera 101, 3 notti, richieste speciali: 'Late checkout'
// Orario di check-in: DateTime(2024, 6, 15, 14, 30)
// TODO: Crea una prenotazione per 'Mike Chen'
// Camera 205, usa il numero predefinito di notti, richieste speciali: 'Extra pillows'
// Nessun orario di check-in specificato
// TODO: Crea una prenotazione per 'Emma Davis'
// Camera 310, 2 notti, nessuna richiesta speciale, nessun orario di check-in
// TODO: Per ogni prenotazione, nell'ordine:
// 1. Chiama printConfirmation()
// 2. Stampa 'Arrival: [result]' usando getArrivalInfo()
}
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