Từ khóa lớp final
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 40 trên 110.
Đôi khi bạn muốn ngăn một lớp (class) bị mở rộng. Từ khóa (keyword) final, khi áp dụng cho một lớp, sẽ ngăn mọi lớp khác kế thừa từ lớp đó.
final class DatabaseConnection {
String connectionString;
DatabaseConnection(this.connectionString);
void connect() {
print('Connected to $connectionString');
}
}
// Điều này sẽ gây ra lỗi khi biên dịch:
// class CustomConnection extends DatabaseConnection { }Đánh dấu một lớp là final rất hữu ích khi việc mở rộng lớp đó có thể phá vỡ hành vi dự kiến hoặc các đảm bảo bảo mật. Ví dụ, một lớp quản lý tài nguyên nhạy cảm có thể cần đảm bảo rằng các phương thức của nó không bị ghi đè theo những cách ngoài dự kiến.
Dart 3 cũng giới thiệu các từ bổ nghĩa liên quan: base buộc các lớp con phải dùng extends (không dùng implements), còn sealed giới hạn việc kế thừa trong cùng một thư viện. Trước mắt, hãy tập trung vào final, cách đơn giản nhất để khóa hoàn toàn một lớp.
Dùng các lớp final khi bạn chắc chắn thiết kế lớp đã hoàn chỉnh và việc kế thừa chỉ gây ra vấn đề. Tuy nhiên, đừng dùng quá nhiều, vì hầu hết các lớp đều có lợi khi vẫn cho phép mở rộng.
Thử thách
DễHãy xây dựng một hệ thống cấu hình an toàn để minh họa khi nào và vì sao bạn nên ngăn một lớp được mở rộng. Bạn sẽ tạo một lớp final để quản lý các thiết lập ứng dụng, đảm bảo hành vi của lớp không thể bị thay đổi thông qua tính kế thừa.
Bạn sẽ sắp xếp code vào hai tệp:
config.dart: Định nghĩa các lớp cấu hình tại đây:- Một
final class AppConfigkhông thể được mở rộng. Lớp này cần có thuộc tínhString appNamevàString version, một hàm khởi tạo nhận cả hai giá trị, cùng phương thứcdisplay()để in ra[appName] v[version] - Một lớp
Featurethông thường (không phải final), có thuộc tínhString namevàbool enabled, một hàm khởi tạo nhận cả hai giá trị, cùng phương thứcstatus()để in ra[name]: [enabled ? 'ON' : 'OFF'] - Một lớp
ExperimentalFeaturekế thừaFeaturevà bổ sung thuộc tínhString warning. Ghi đèstatus()bằng@overrideđể gọi phiên bản của lớp cha trước bằngsuper.status(), sau đó in raWarning: [warning]
- Một
main.dart: Nhập tệp cấu hình và minh họa sự khác biệt giữa lớp final và lớp thông thường:- Tạo một
AppConfigvới appName là'MyApp'và version là'2.0.1', sau đó gọidisplay() - In ra một dòng trống
- Tạo một
Featurecó name là'Dark Mode'và enabled làtrue, sau đó gọistatus() - In ra một dòng trống
- Tạo một
ExperimentalFeaturecó name là'AI Assistant', enabled làfalsevà warning là'May be unstable', sau đó gọistatus()
- Tạo một
Hãy chú ý rằng AppConfig được khai báo là final vì hành vi cấu hình của lớp này cần luôn nhất quán và an toàn. Không lớp con nào có thể thay đổi cách quản lý các thiết lập. Trong khi đó, Feature vẫn có thể được mở rộng, cho phép ExperimentalFeature bổ sung hành vi chuyên biệt.
Đầu ra dự kiến:
MyApp v2.0.1
Dark Mode: ON
AI Assistant: OFF
Warning: May be unstableTự làm thử
import 'config.dart';
void main() {
// TODO: Tạo một AppConfig với appName là 'MyApp' và version là '2.0.1'
// Sau đó gọi display()
// TODO: In ra một dòng trống
// TODO: Tạo một Feature với name là 'Dark Mode' và enabled là true
// Sau đó gọi status()
// TODO: In ra một dòng trống
// TODO: Tạo một ExperimentalFeature với name là 'AI Assistant',
// enabled là false và warning là 'May be unstable'
// Sau đó gọi status()
}
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