Thành viên công khai và riêng tư
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 30 trên 110.
Tính đóng gói là một trong những nguyên tắc cốt lõi của lập trình hướng đối tượng. Nguyên tắc này giúp kiểm soát quyền truy cập vào dữ liệu bên trong một lớp, quyết định những gì bên ngoài có thể thấy và những gì cần được ẩn đi.
Trong Dart, các thành viên của lớp (trường và phương thức) mặc định là công khai. Điều này có nghĩa là mọi đoạn code đều có thể truy cập trực tiếp vào chúng:
class BankAccount {
String owner;
double balance;
BankAccount(this.owner, this.balance);
}
var account = BankAccount('Alice', 1000);
account.balance = -500; // Ai cũng có thể sửa trực tiếp giá trị này!Điều này có vấn đề. Không có gì ngăn bạn đặt số dư không hợp lệ.
Để bảo vệ dữ liệu nội bộ, Dart sử dụng thành viên riêng tư. Một thành viên trở thành riêng tư khi tên của nó bắt đầu bằng dấu gạch dưới _:
class BankAccount {
String owner;
double _balance; // Riêng tư: bắt đầu bằng dấu gạch dưới
BankAccount(this.owner, this._balance);
double get balance => _balance; // Truy cập có kiểm soát
}Giờ đây, bạn không thể truy cập trực tiếp vào _balance từ bên ngoài thư viện nơi lớp được định nghĩa. Code bên ngoài phải dùng getter công khai. Cách này giúp bạn kiểm soát việc đọc và sửa đổi dữ liệu, đảm bảo các đối tượng luôn ở trạng thái hợp lệ.
Thử thách
DễHãy cùng xây dựng một trình quản lý mật khẩu đơn giản để minh họa sự khác biệt giữa thành viên công khai (public member) và thành viên riêng tư (private member). Bạn sẽ thấy tiền tố gạch dưới giúp bảo vệ dữ liệu nhạy cảm khỏi bị truy cập trực tiếp từ bên ngoài thư viện của lớp.
Bạn sẽ tạo hai tệp để sắp xếp code:
credential.dart: Định nghĩa lớpCredentialđể lưu thông tin đăng nhập cho một trang web. Lớp này cần có:- Một
String websitecông khai, ai cũng có thể biết đây là trang web nào - Một
String usernamecông khai, tên người dùng có thể hiển thị - Một
String _passwordriêng tư, mật khẩu thật cần được bảo vệ - Một hàm khởi tạo nhận cả ba giá trị
- Một getter công khai
passwordtrả về_passwordriêng tư để kiểm soát quyền truy cập - Một phương thức
getMaskedPassword()trả về mật khẩu với tất cả ký tự được thay bằng dấu hoa thị*(có độ dài bằng mật khẩu thật) - Một phương thức
displayCredential()in thông tin đăng nhập một cách an toàn, hiển thị mật khẩu đã được che chứ không phải mật khẩu thật
- Một
main.dart: Nhập lớp thông tin đăng nhập và minh họa cách tính đóng gói bảo vệ mật khẩu:- Tạo thông tin đăng nhập cho trang web
'github.com', tên người dùng'dev_user'và mật khẩu'secret123' - Tạo một thông tin đăng nhập khác cho trang web
'email.com', tên người dùng'john_doe'và mật khẩu'myP@ss' - Với mỗi thông tin đăng nhập, gọi
displayCredential(), sau đó inActual password length: [length]bằng getter công khai để truy cập độ dài mật khẩu
- Tạo thông tin đăng nhập cho trang web
Phương thức displayCredential() cần in theo định dạng sau:
--- Credential ---
Website: [website]
Username: [username]
Password: [maskedPassword]Đầu ra dự kiến:
--- Credential ---
Website: github.com
Username: dev_user
Password: *********
Actual password length: 9
--- Credential ---
Website: email.com
Username: john_doe
Password: ******
Actual password length: 6Tự làm thử
import 'credential.dart';
void main() {
// TODO: Tạo thông tin đăng nhập cho github.com
// website: 'github.com', username: 'dev_user', password: 'secret123'
// TODO: Gọi displayCredential() trên thông tin đăng nhập đầu tiên
// TODO: In ra độ dài mật khẩu thực tế bằng getter công khai
// Định dạng: "Actual password length: [length]"
// TODO: Tạo thông tin đăng nhập cho email.com
// website: 'email.com', username: 'john_doe', password: 'myP@ss'
// TODO: Gọi displayCredential() trên thông tin đăng nhập thứ hai
// TODO: In ra độ dài mật khẩu thực tế bằng getter công khai
}
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