An toàn với giá trị null trong lớp
Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 28 trên 110.
Khi thiết kế lớp, bạn cần quyết định thuộc tính nào là bắt buộc và thuộc tính nào là tùy chọn. Tính an toàn với giá trị null ảnh hưởng đến cách bạn khai báo biến của đối tượng và viết hàm khởi tạo.
Bạn phải khởi tạo các trường không thể nhận giá trị null trước khi phần thân hàm khởi tạo chạy. Bạn có thể làm việc này bằng danh sách khởi tạo, tham số của hàm khởi tạo hoặc giá trị mặc định:
class User {
String name; // Phải khởi tạo
String? bio; // Không bắt buộc, có thể là null
int age = 0; // Có giá trị mặc định
User(this.name); // name được khởi tạo qua tham số
}Với các trường có thể nhận giá trị null, bạn có thể để chúng chưa được khởi tạo vì mặc định chúng có giá trị null. Điều này hữu ích với dữ liệu không bắt buộc:
class Product {
String title;
String? description; // Mô tả sản phẩm không bắt buộc
double? discount; // Mặc định không có giảm giá
Product(this.title);
}
var item = Product('Laptop');
print(item.description); // null
print(item.discount); // nullKhi truy cập các trường có thể nhận giá trị null, hãy dùng các toán tử nhận biết null mà bạn đã học:
class Order {
String id;
User? customer;
Order(this.id);
String getCustomerName() {
return customer?.name ?? 'Guest';
}
}Từ khóa required trong các tham số có tên đảm bảo bên gọi cung cấp các giá trị thiết yếu:
class Account {
String email;
String? phone;
Account({required this.email, this.phone});
}
var acc = Account(email: 'test@mail.com'); // phone là tùy chọnBằng cách cân nhắc kỹ khi chọn trường có thể nhận giá trị null và trường không thể nhận giá trị null, bạn tạo ra các lớp thể hiện rõ dữ liệu nào là thiết yếu và dữ liệu nào là tùy chọn.
Thử thách
DễHãy xây dựng hệ thống đặt phòng khách sạn để minh họa cách thiết kế các lớp với sự kết hợp hợp lý giữa những trường bắt buộc và tùy chọn bằng cách sử dụng tính an toàn null.
Bạn sẽ sắp xếp code thành hai tệp:
reservation.dart: Định nghĩa lớpReservationđại diện cho một lượt đặt phòng khách sạn. Mỗi lượt đặt phòng cần một số thông tin thiết yếu, nhưng một số chi tiết là tùy chọn và khách có thể cung cấp hoặc không. Lớp của bạn cần có:String guestNamekhông nullable, mỗi lượt đặt phòng phải có tên kháchint roomNumberkhông nullable, mỗi lượt đặt phòng phải được chỉ định một phòngint nightskhông nullable với giá trị mặc định là1, thời gian lưu trú tối thiểu là một đêmString? specialRequestsnullable, khách có thể có các yêu cầu đặc biệtDateTime? checkInTimenullable, có thể chưa biết chính xác thời gian khách đến- Một hàm khởi tạo dùng tham số có tên với
requiredchoguestNamevàroomNumber, cònnightslà tùy chọn với giá trị mặc định - Một phương thức
getRequestsSummary()trả về các yêu cầu đặc biệt nếu có, hoặc'No special requests'bằng toán tử?? - Một phương thức
getArrivalInfo()trả về biểu diễn dạng chuỗi của thời gian nhận phòng bằng?., hoặc trả vềnullnếu chưa được đặt - Một phương thức
printConfirmation()hiển thị thông tin đặt phòng
main.dart: Nhập lớp đặt phòng và tạo các lượt đặt phòng thể hiện những cách kết hợp khác nhau giữa dữ liệu bắt buộc và tùy chọn:- Tạo lượt đặt phòng cho khách
'Sarah Johnson'ở phòng101trong3đêm, với yêu cầu đặc biệt'Late checkout'và đặt thời gian nhận phòng thànhDateTime(2024, 6, 15, 14, 30) - Tạo lượt đặt phòng cho khách
'Mike Chen'ở phòng205(dùng số đêm mặc định), chỉ đặt yêu cầu đặc biệt thành'Extra pillows' - Tạo lượt đặt phòng cho khách
'Emma Davis'ở phòng310trong2đêm (để cả hai trường tùy chọn là null) - Lần lượt với từng lượt đặt phòng, gọi
printConfirmation(), sau đó inArrival: [result]bằnggetArrivalInfo()
- Tạo lượt đặt phòng cho khách
Phương thức printConfirmation() cần in theo định dạng sau:
=== Reservation Confirmed ===
Guest: [guestName]
Room: [roomNumber]
Nights: [nights]
Requests: [getRequestsSummary()]Đầu ra dự kiến:
=== 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: nullTự làm thử
import 'reservation.dart';
void main() {
// TODO: Tạo đặt phòng cho 'Sarah Johnson'
// Phòng 101, 3 đêm, yêu cầu đặc biệt: 'Late checkout'
// Thời gian nhận phòng: DateTime(2024, 6, 15, 14, 30)
// TODO: Tạo đặt phòng cho 'Mike Chen'
// Phòng 205, dùng số đêm mặc định, yêu cầu đặc biệt: 'Extra pillows'
// Không chỉ định thời gian nhận phòng
// TODO: Tạo đặt phòng cho 'Emma Davis'
// Phòng 310, 2 đêm, không có yêu cầu đặc biệt, không có thời gian nhận phòng
// TODO: Với từng đặt phòng theo thứ tự:
// 1. Gọi printConfirmation()
// 2. In ra 'Arrival: [result]' bằng getArrivalInfo()
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiThư viện và câu lệnh importGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcBiến thể hiệnKiến thức cơ bản về hàm khởi tạoÔn tập: Máy tính đơn giản4An toàn với giá trị null
Giới thiệu về an toàn với giá trị nullCó thể null và không thể nullToán tử ? và !Từ khóa late và an toàn với giá trị nullToán tử xử lý nullAn toàn với giá trị null trong lớpÔn tập: hệ thống hồ sơ người dùng7Lớp trừu tượng và interface
Lớp trừu tượngPhương thức trừu tượngInterface trong DartInterface ngầm địnhTriển khai và kế thừaNhiều interfaceÔn tập: Máy tính hình10Bộ sưu tập và kiểu tổng quát
Tổng quan về List, Set và MapBộ sưu tập an toàn về kiểuLớp tổng quátPhương thức tổng quátRàng buộc kiểu tổng quátIterable và IteratorÔn tập: Lưu trữ tổng quát2Hàm khởi tạo trong Dart
Hàm khởi tạo mặc địnhHàm khởi tạo có tênDanh sách khởi tạoHàm khởi tạo hằng sốHàm khởi tạo nhà máyHàm khởi tạo chuyển hướngÔn tập: Trình tạo hình dạng5Đóng gói
Thành viên công khai và riêng tưQuy ước tiền tố _Tính riêng tư ở cấp thư việnTìm hiểu sâu về getter và setterChe giấu thông tinÔn tập: hồ sơ học sinh8Mixin
Giới thiệu về MixinTạo MixinSử dụng nhiều MixinTừ khóa on trong MixinMixin và kế thừaMixin và giao diệnÔn tập: hệ thống động vật3Thuộc tính của lớp
Thành viên instance và thành viên tĩnhTrường final và constBiến latePhương thức và trường tĩnhGetter và setterÔn tập: trình quản lý tài khoản ngân hàng6Kế thừa
Kế thừa cơ bảnTừ khóa superGhi đè phương thứcChú thích @overrideTừ khóa lớp finalHàm khởi tạo và kế thừaÔn tập: phân cấp nhân viên9Đa hình
Khái niệm cơ bản về đa hìnhĐa hình qua giao diệnKiểm tra kiểu lúc chạyToán tử is và asTừ khóa hiệp biếnÔn tập: Bộ xử lý thanh toánTự luyện tập: Trình biên dịch Dart online