Menu
Coddy logo textTech

Bezpieczeństwo wartości null w klasach

Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 28 z 110.

Projektując klasy, musisz zdecydować, które pola są wymagane, a które opcjonalne. Bezpieczeństwo wartości null wpływa na sposób deklarowania zmiennych instancji i pisania konstruktorów.

Pola, które nie dopuszczają wartości null, muszą zostać zainicjalizowane przed uruchomieniem treści konstruktora. Możesz to zrobić za pomocą list inicjalizujących, parametrów konstruktora lub wartości domyślnych:

class User {
  String name;           // Musi zostać zainicjalizowane
  String? bio;           // Opcjonalne — może mieć wartość null
  int age = 0;           // Ma wartość domyślną
  
  User(this.name);       // name jest inicjalizowane przez parametr
}

Pola dopuszczające wartość null możesz pozostawić niezainicjalizowane, ponieważ domyślnie mają wartość null. Jest to przydatne w przypadku danych opcjonalnych:

class Product {
  String title;
  String? description;   // Opcjonalny opis produktu
  double? discount;      // Domyślnie bez rabatu
  
  Product(this.title);
}

var item = Product('Laptop');
print(item.description);  // null
print(item.discount);     // null

Podczas uzyskiwania dostępu do pól dopuszczających wartość null używaj poznanych operatorów obsługujących null:

class Order {
  String id;
  User? customer;
  
  Order(this.id);
  
  String getCustomerName() {
    return customer?.name ?? 'Guest';
  }
}

Słowo kluczowe required w parametrach nazwanych gwarantuje, że wywołujący podadzą niezbędne wartości:

class Account {
  String email;
  String? phone;
  
  Account({required this.email, this.phone});
}

var acc = Account(email: 'test@mail.com');  // phone jest opcjonalne

Świadomie wybierając między polami dopuszczającymi wartość null a polami niedopuszczającymi wartości null, tworzysz klasy, które jasno określają, które dane są niezbędne, a które opcjonalne.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system rezerwacji hotelowych, który pokaże, jak projektować klasy z przemyślanym połączeniem wymaganych i opcjonalnych pól przy użyciu bezpieczeństwa nulli.

Podzielisz kod na dwa pliki:

  • reservation.dart: Zdefiniuj klasę Reservation, która reprezentuje rezerwację hotelową. Każda rezerwacja wymaga określonych niezbędnych informacji, ale niektóre szczegóły są opcjonalnymi dodatkami, które goście mogą podać albo nie. Twoja klasa powinna mieć:
    • Nieprzyjmujące wartości null String guestName — każda rezerwacja musi zawierać imię i nazwisko gościa
    • Nieprzyjmujące wartości null int roomNumber — do każdej rezerwacji musi być przypisany pokój
    • Nieprzyjmujące wartości null int nights z domyślną wartością 1 — minimalny pobyt to jedna noc
    • Przyjmujące wartość null String? specialRequests — goście mogą mieć specjalne życzenia
    • Przyjmujące wartość null DateTime? checkInTime — dokładna godzina przyjazdu może nie być znana
    • Konstruktor z parametrami nazwanymi, w którym required jest użyte dla guestName i roomNumber, a nights jest opcjonalne i ma domyślną wartość
    • Metodę getRequestsSummary(), która zwraca podane specjalne życzenia albo 'No special requests', używając operatora ??
    • Metodę getArrivalInfo(), która zwraca tekstową reprezentację godziny zameldowania przy użyciu ?. albo null, jeśli godzina nie została ustawiona
    • Metodę printConfirmation(), która wyświetla szczegóły rezerwacji
  • main.dart: Zaimportuj klasę rezerwacji i utwórz rezerwacje prezentujące różne kombinacje wymaganych i opcjonalnych danych:
    • Utwórz rezerwację dla gościa 'Sarah Johnson' w pokoju 101 na 3 noce, ze specjalnymi życzeniami 'Late checkout' i godziną zameldowania ustawioną na DateTime(2024, 6, 15, 14, 30)
    • Utwórz rezerwację dla gościa 'Mike Chen' w pokoju 205 (użyj domyślnej liczby nocy), ustawiając tylko specjalne życzenia na 'Extra pillows'
    • Utwórz rezerwację dla gościa 'Emma Davis' w pokoju 310 na 2 noce (pozostaw oba pola opcjonalne jako null)
    • Dla każdej rezerwacji, w podanej kolejności, wywołaj printConfirmation(), a następnie wypisz Arrival: [result], używając getArrivalInfo()

Metoda printConfirmation() powinna wypisywać dane w następującym formacie:

=== Reservation Confirmed ===
Guest: [guestName]
Room: [roomNumber]
Nights: [nights]
Requests: [getRequestsSummary()]

Oczekiwany wynik:

=== 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: null

Spróbuj swoich sił

import 'reservation.dart';

void main() {
  // TODO: Utwórz rezerwację dla 'Sarah Johnson'
  // Pokój 101, 3 noce, życzenia specjalne: 'Late checkout'
  // Godzina zameldowania: DateTime(2024, 6, 15, 14, 30)
  
  // TODO: Utwórz rezerwację dla 'Mike Chen'
  // Pokój 205, użyj domyślnej liczby nocy, życzenia specjalne: 'Extra pillows'
  // Nie podano godziny zameldowania
  
  // TODO: Utwórz rezerwację dla 'Emma Davis'
  // Pokój 310, 2 noce, bez życzeń specjalnych i bez godziny zameldowania
  
  // TODO: Dla każdej rezerwacji po kolei:
  // 1. Wywołaj printConfirmation()
  // 2. Wypisz 'Arrival: [result]', używając getArrivalInfo()
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Dart online