Chú thích @override
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 39 trên 110.
Chú thích @override là dấu hiệu cho biết bạn cố ý thay thế một phương thức của lớp cha. Đây là một thông lệ tốt để Dart và các nhà phát triển khác nhận biết điều đó. Dù việc ghi đè phương thức vẫn hoạt động khi không có chú thích này, dùng @override sẽ giúp tăng độ an toàn.
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name barks: Woof!');
}
}Chú thích này mang lại hai lợi ích chính. Thứ nhất, nó ghi lại rõ ràng ý định của bạn: bất kỳ ai đọc code đều biết ngay phương thức này tồn tại trong lớp cha. Thứ hai, trình phân tích của Dart sẽ cảnh báo nếu phương thức ở lớp cha thực sự không tồn tại, giúp phát hiện sớm lỗi chính tả và sai sót khi tái cấu trúc.
Hãy xem điều gì xảy ra nếu bạn viết sai tên phương thức mà không có @override:
class Cat extends Animal {
Cat(String name) : super(name);
void speek() { // Lỗi gõ nhầm! Không có cảnh báo nếu thiếu @override
print('$name meows');
}
}Nếu không có chú thích, Dart sẽ cho rằng bạn đang tạo một phương thức mới tên là speek(). Khi có @override, trình phân tích sẽ báo ngay rằng lớp cha không có phương thức nào như vậy. Chú thích đơn giản này giúp ngăn những lỗi khó phát hiện về sau.
Thử thách
DễHãy xây dựng một hệ thống trình phát nội dung đa phương tiện để minh họa tầm quan trọng của chú thích @override khi tùy chỉnh hành vi được kế thừa. Bạn sẽ tạo các loại nội dung đa phương tiện khác nhau, mỗi loại phát nội dung theo cách riêng.
Bạn sẽ sắp xếp code vào hai tệp:
media.dart: Định nghĩa hệ thống phân cấp nội dung đa phương tiện tại đây:- Một lớp (class)
Mediacó thuộc tính (property)String title, hàm khởi tạo (constructor) nhận tiêu đề và phương thức (method)play()in raPlaying: [title] - Một lớp
Songkế thừa (inheritance) từMediavà bổ sung thuộc tínhString artist. Dùng chú thích@overridevà ghi đèplay()để in raPlaying song: [title] by [artist] - Một lớp
Videokế thừa từMediavà bổ sung thuộc tínhint duration(tính bằng giây). Dùng@overridevà ghi đèplay()để gọi phiên bản của lớp cha bằngsuper.play()trước, sau đó in raDuration: [duration] seconds
- Một lớp (class)
main.dart: Nhập tệp nội dung đa phương tiện và minh họa các phương thức đã ghi đè:- Tạo một đối tượng
Mediacó tiêu đề'Generic Content'và gọiplay() - In một dòng trống
- Tạo một
Songcó tiêu đề'Imagine'và nghệ sĩ'John Lennon', rồi gọiplay() - In một dòng trống
- Tạo một
Videocó tiêu đề'Dart Tutorial'và thời lượng360, rồi gọiplay()
- Tạo một đối tượng
Chú thích @override ghi lại ý định của bạn và giúp phát hiện lỗi. Nếu vô tình viết sai play() thành plya(), chú thích sẽ cảnh báo rằng lớp cha không có phương thức như vậy.
Đầu ra dự kiến:
Playing: Generic Content
Playing song: Imagine by John Lennon
Playing: Dart Tutorial
Duration: 360 secondsTự làm thử
import 'media.dart';
void main() {
// TODO: Tạo một đối tượng Media có tiêu đề 'Generic Content' rồi gọi play()
// TODO: In ra một dòng trống
// TODO: Tạo một Song có tiêu đề 'Imagine' và nghệ sĩ 'John Lennon', rồi gọi play()
// TODO: In ra một dòng trống
// TODO: Tạo một Video có tiêu đề 'Dart Tutorial' và thời lượng 360, rồi gọi play()
}
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