Menu
CoddyTech

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ự.

challenge icon

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ớp Product để 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 name công khai
    • Một thuộc tính double _price riêng tư
    • Một thuộc tính int _quantity riêng tư
    • Một hàm khởi tạo nhận cả ba giá trị
    • Một getter price trả về giá riêng tư
    • Một setter price chỉ chấp nhận giá trị lớn hơn 0 (bỏ qua giá trị không hợp lệ)
    • Một getter quantity trả về số lượng riêng tư
    • Một setter quantity chỉ chấp nhận giá trị từ 0 trở lên (bỏ qua giá trị âm)
    • Một getter được tính toán totalValue trả về _price * _quantity
    • Một getter được tính toán isInStock trả về true nếu số lượng lớn hơn 0
    • Một getter chỉ đọc sku tạ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ụ: LAP25 cho "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
  • 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.99 và số lượng 25
    • 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]

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: LAP0

Tự 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]"
}
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch Dart online