Tìm hiểu sâu về getter và setter
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 33 trên 110.
Getter và setter trở thành công cụ mạnh mẽ để đóng gói khi kết hợp với các trường private. Chúng giúp bạn cung cấp một giao diện công khai rõ ràng mà vẫn kiểm soát hoàn toàn cách truy cập và chỉnh sửa dữ liệu.
Một mẫu thường gặp là kết hợp một trường riêng tư với một getter công khai và một setter có bước kiểm tra hợp lệ:
class Temperature {
double _celsius = 0;
double get celsius => _celsius;
set celsius(double value) {
if (value < -273.15) {
_celsius = -273.15; // Giới hạn dưới là độ không tuyệt đối
} else {
_celsius = value;
}
}
}Các phương thức thiết lập (setter) có thể thực thi quy tắc nghiệp vụ, giúp đối tượng của bạn không bao giờ rơi vào trạng thái không hợp lệ.
Bạn cũng có thể tạo getter tính toán để suy ra giá trị từ dữ liệu riêng tư:
class Rectangle {
double _width;
double _height;
Rectangle(this._width, this._height);
double get area => _width * _height; // Được tính toán
double get perimeter => 2 * (_width + _height);
double get width => _width;
set width(double value) {
if (value > 0) _width = value;
}
}Đôi khi bạn muốn chỉ cho phép đọc. Chỉ cần cung cấp getter mà không có setter:
class Order {
final DateTime _createdAt = DateTime.now();
DateTime get createdAt => _createdAt; // Chỉ đọc
}Mẫu này cho phép code bên ngoài xem dữ liệu nhưng không thể sửa đổi. Thuộc tính riêng tư kết hợp với getter duy nhất tạo ra quyền truy cập chỉ đọc thực sự.
Thử thách
DễHãy xây dựng một hệ thống quản lý hàng tồn kho để cho thấy sức mạnh của getter và setter trong việc kiểm soát quyền truy cập dữ liệu. Bạn sẽ tạo một lớp bảo vệ dữ liệu nội bộ, đồng thời cung cấp các thuộc tính được tính toán và tính năng xác thực.
Bạn sẽ sắp xếp code thành hai tệp:
product.dart: Định nghĩa lớpProductđể quản lý hàng tồn kho bằng cách đóng gói phù hợp. Sản phẩm cần có:- Một thuộc tính
String namecông khai - Một thuộc tính
double _priceriêng tư - Một thuộc tính
int _quantityriêng tư - Một hàm khởi tạo nhận cả ba giá trị
- Một getter
pricetrả về giá riêng tư - Một setter
pricechỉ chấp nhận giá trị lớn hơn0(bỏ qua giá trị không hợp lệ) - Một getter
quantitytrả về số lượng riêng tư - Một setter
quantitychỉ chấp nhận giá trị từ0trở lên (bỏ qua giá trị âm) - Một getter được tính toán
totalValuetrả về_price * _quantity - Một getter được tính toán
isInStocktrả vềtruenếu số lượng lớn hơn0 - Một getter chỉ đọc
skutạo SKU đơn giản bằng cách trả về 3 ký tự đầu tiên của tên ở dạng chữ hoa, theo sau là số lượng (ví dụ:LAP25cho "Laptop" có số lượng là 25) - Một phương thức
displayProduct()hiển thị thông tin chi tiết về sản phẩm
- Một thuộc tính
main.dart: Nhập lớp sản phẩm và minh họa cách getter và setter kiểm soát quyền truy cập:- Tạo một sản phẩm tên là
'Laptop'với giá999.99và số lượng25 - Gọi
displayProduct() - In ra
In stock: [isInStock] - In ra
SKU: [sku] - Thử đặt giá thành
-50.0(giá trị này sẽ bị bỏ qua) - Đặt giá thành
899.99(thay đổi hợp lệ) - Thử đặt số lượng thành
-10(giá trị này sẽ bị bỏ qua) - Đặt số lượng thành
0(thay đổi hợp lệ) - Gọi
displayProduct() - In ra
In stock: [isInStock] - In ra
SKU: [sku]
- Tạo một sản phẩm tên là
Phương thức displayProduct() cần in ra theo định dạng sau:
--- Product Info ---
Name: [name]
Price: $[price]
Quantity: [quantity]
Total Value: $[totalValue]Đầu ra dự kiến:
--- Product Info ---
Name: Laptop
Price: $999.99
Quantity: 25
Total Value: $24999.75
In stock: true
SKU: LAP25
--- Product Info ---
Name: Laptop
Price: $899.99
Quantity: 0
Total Value: $0.0
In stock: false
SKU: LAP0Tự làm thử
import 'product.dart';
void main() {
// TODO: Tạo sản phẩm tên 'Laptop' với giá 999.99 và số lượng 25
// TODO: Gọi displayProduct()
// TODO: In ra "In stock: [isInStock]"
// TODO: In ra "SKU: [sku]"
// TODO: Thử đặt giá thành -50.0 (thao tác này phải bị bỏ qua)
// TODO: Đặt giá thành 899.99 (thay đổi hợp lệ)
// TODO: Thử đặt số lượng thành -10 (thao tác này phải bị bỏ qua)
// TODO: Đặt số lượng thành 0 (thay đổi hợp lệ)
// TODO: Gọi displayProduct()
// TODO: In ra "In stock: [isInStock]"
// TODO: In ra "SKU: [sku]"
}
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