Che giấu thông tin
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 34 trên 110.
Ẩn thông tin là nguyên tắc nền tảng của tính đóng gói, tức là một lớp nên ẩn cách hoạt động bên trong và chỉ để lộ những gì cần thiết. Bạn đã học các cơ chế (trường riêng tư, hàm lấy giá trị, hàm đặt giá trị), nhưng mục tiêu thực sự là thiết kế các lớp dễ sử dụng và khó dùng sai.
Hãy hình dung một lớp quản lý mật khẩu của người dùng. Logic lưu trữ nội bộ và băm mật khẩu phải được ẩn hoàn toàn:
class UserAccount {
String _username;
String _passwordHash;
UserAccount(this._username, String password)
: _passwordHash = _hashPassword(password);
static String _hashPassword(String password) {
return 'hashed_$password'; // Ví dụ đơn giản hóa
}
bool verifyPassword(String password) {
return _passwordHash == _hashPassword(password);
}
String get username => _username;
}Code bên ngoài không bao giờ thấy mã băm mật khẩu hoặc biết cách lưu trữ mã đó. Chúng chỉ cần gọi verifyPassword(). Sự tách biệt này có nghĩa là bạn có thể thay đổi hoàn toàn thuật toán băm mà không ảnh hưởng đến code sử dụng lớp này.
Điều quan trọng là bạn hãy nhìn lớp từ bên ngoài vào.
Hãy tự hỏi: “Người sử dụng lớp này thực sự cần gì?” Chỉ hiển thị những gì họ cần, còn mọi thứ khác thì giữ riêng tư. Cách này tạo ra ranh giới rõ ràng giữa chức năng của lớp (giao diện công khai) và cách lớp thực hiện chức năng đó (phần triển khai riêng tư).
Thử thách
DễHãy xây dựng một hệ thống ví an toàn để thấy cách tính đóng gói thông tin được áp dụng. Bạn sẽ tạo một ví kỹ thuật số quản lý số dư và lịch sử giao dịch của người dùng, đồng thời giữ kín hoàn toàn mọi chi tiết nội bộ nhạy cảm với code bên ngoài.
Bạn sẽ sắp xếp code thành hai tệp:
wallet.dart: Tạo một lớpWalletquản lý tiền an toàn. Ví nên công khai tên chủ sở hữu, nhưng ẩn mọi thứ khác sau một giao diện công khai rõ ràng:- Số dư nội bộ và nhật ký giao dịch phải ở chế độ riêng tư. Code bên ngoài không bao giờ được biết bạn lưu trữ hoặc theo dõi tiền như thế nào
- Một phương thức riêng tư sẽ xử lý việc ghi lại giao dịch nội bộ (lưu các mục như
"Deposit: $50.0"hoặc"Withdrawal: $30.0") - Cung cấp phương thức công khai
deposit(double amount)để nạp tiền (chỉ khi số tiền dương) và ghi lại giao dịch nội bộ - Cung cấp phương thức công khai
withdraw(double amount)để rút tiền chỉ khi số dư đủ và số tiền dương, đồng thời ghi lại giao dịch nội bộ. Trả vềtruenếu thành công, nếu không thì trả vềfalse - Cung cấp getter công khai
balanceđể trả về số dư hiện tại (chỉ đọc) - Cung cấp phương thức công khai
getTransactionCount()để trả về số giao dịch đã ghi lại (không tiết lộ danh sách giao dịch thực tế) - Cung cấp phương thức công khai
getLastTransaction()để trả về chuỗi giao dịch gần đây nhất hoặc"No transactions"nếu chưa có giao dịch nào - Thêm phương thức
printSummary()để hiển thị trạng thái ví
main.dart: Nhập ví và minh họa cách tính đóng gói thông tin tạo ra một giao diện rõ ràng, an toàn:- Tạo ví cho chủ sở hữu
"Sarah" - Nạp
100.0 - Nạp
50.0 - Thử rút
200.0và in ra"Withdrawal of 200.0: [success/failed]"tùy theo kết quả - Rút
30.0và in ra"Withdrawal of 30.0: [success/failed]" - Gọi
printSummary() - In ra
"Transaction count: [count]" - In ra
"Last transaction: [transaction]"
- Tạo ví cho chủ sở hữu
Phương thức printSummary() sẽ in ra:
=== Wallet Summary ===
Owner: [ownerName]
Balance: $[balance]Hãy để ý cách code bên ngoài có thể tương tác với ví thông qua các phương thức rõ ràng, có mục đích mà không cần biết số dư được lưu trữ ra sao hoặc các giao dịch được theo dõi nội bộ như thế nào. Chi tiết triển khai được giữ kín hoàn toàn. Bạn có thể thay đổi cách lưu trữ giao dịch mà không ảnh hưởng đến bất kỳ code nào sử dụng ví.
Đầu ra dự kiến:
Withdrawal of 200.0: failed
Withdrawal of 30.0: success
=== Wallet Summary ===
Owner: Sarah
Balance: $120.0
Transaction count: 3
Last transaction: Withdrawal: $30.0Tự làm thử
import 'wallet.dart';
void main() {
// TODO: Tạo ví cho chủ sở hữu "Sarah"
// TODO: Nạp 100.0 vào ví
// TODO: Nạp 50.0 vào ví
// TODO: Thử rút 200.0 và in kết quả
// Định dạng: "Withdrawal of 200.0: [success/failed]"
// TODO: Rút 30.0 và in kết quả
// Định dạng: "Withdrawal of 30.0: [success/failed]"
// TODO: Gọi printSummary()
// TODO: In số lượng giao dịch
// Định dạng: "Transaction count: [count]"
// TODO: In giao dịch cuối cùng
// Định dạng: "Last transaction: [transaction]"
}
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