Menu
CoddyTech

Kiểm tra tính hợp lệ trong hàm gán

Thuộc phần Lập trình hướng đối tượng trong hành trình C của Coddy. Bài học 20 trên 61.

Trong bài học trước, chúng ta đã tạo các hàm thiết lập cơ bản chỉ gán giá trị. Nhưng cách này bỏ lỡ một lợi ích quan trọng của tính đóng gói: khả năng bảo vệ dữ liệu bằng cách thêm logic xác thực.

Hãy xem xét một Counter không bao giờ được âm. Nếu không đóng gói, bất kỳ ai cũng có thể viết c->value = -50 và làm hỏng trạng thái. Với một hàm đặt giá trị (setter), bạn kiểm soát những giá trị được phép:

// counter.c
void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // Âm thầm từ chối đầu vào không hợp lệ
    }
    c->value = new_value;
}

Giờ đây, các giá trị âm sẽ được bỏ qua.

Bạn cũng có thể chọn trả về mã trạng thái để cho biết thành công hay thất bại:

int counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return 0;  // Thất bại
    }
    c->value = new_value;
    return 1;  // Thành công
}

Mẫu này giúp bên gọi biết thao tác có thành công hay không. Điểm mấu chốt là các hàm thiết lập không chỉ dùng để gán giá trị: chúng còn là người gác cổng, thực thi các quy tắc về trạng thái mà đối tượng có thể có. Đây là sức mạnh thực sự của tính đóng gói: đối tượng tự duy trì tính toàn vẹn của mình, bất kể code bên ngoài cố làm gì.

challenge icon

Thử thách

Dễ

Hãy tạo một module Temperature bảo vệ dữ liệu bằng cách kiểm tra tính hợp lệ trong hàm setter. Bạn sẽ tạo bộ theo dõi nhiệt độ chỉ chấp nhận các giá trị trong phạm vi hợp lệ, qua đó cho thấy hàm setter kiểm soát trạng thái của đối tượng như thế nào.

Bạn sẽ tạo ba tệp:

  • temperature.h: Giao diện công khai dùng mẫu con trỏ mờ. Khai báo kiểu Temperature chỉ bằng khai báo trước. Khai báo các hàm sau:
    • create_temperature: nhận số nguyên biểu thị độ ban đầu và trả về con trỏ Temperature
    • free_temperature: giải phóng bộ nhớ đã cấp phát
    • temp_get_degrees: hàm getter trả về giá trị nhiệt độ hiện tại
    • temp_set_degrees: hàm setter trả về int (1 nếu thành công, 0 nếu thất bại)
    Dùng các trình bảo vệ include với ký hiệu TEMPERATURE_H.
  • temperature.c: Định nghĩa struct Temperature thực tế với thành viên int degrees được ẩn đi. Cài đặt tất cả các hàm. Điểm mấu chốt là hàm setter. Hàm này chỉ nên chấp nhận các giá trị từ -50 đến 150 (bao gồm cả hai đầu mút). Nếu giá trị nằm ngoài phạm vi này, hãy trả về 0 và giữ nguyên nhiệt độ. Nếu giá trị hợp lệ, hãy cập nhật giá trị rồi trả về 1.
  • main.c: Minh họa cách kiểm tra tính hợp lệ bằng cách thử đặt cả nhiệt độ hợp lệ lẫn không hợp lệ, cho thấy các giá trị không hợp lệ bị từ chối còn các giá trị hợp lệ được chấp nhận.

Bạn sẽ nhận ba đầu vào: nhiệt độ ban đầu, nhiệt độ hợp lệ cần đặt (trong phạm vi) và nhiệt độ không hợp lệ cần thử đặt (ngoài phạm vi).

Trong tệp main, hãy tạo một Temperature với giá trị ban đầu rồi in giá trị đó ra. Tiếp theo, hãy thử đặt nhiệt độ không hợp lệ. Vì giá trị này sẽ bị từ chối, hãy in kết quả và cho thấy giá trị vẫn không thay đổi. Cuối cùng, hãy đặt nhiệt độ hợp lệ, in kết quả thành công và cho thấy giá trị đã cập nhật. Giải phóng bộ nhớ và xác nhận đã dọn dẹp.

In đầu ra theo định dạng này:

Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
Freed

Ví dụ, với đầu vào 25, 100 và 200, đầu ra sẽ là:

Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
Freed

Ví dụ này cho thấy sức mạnh thực sự của tính đóng gói. Hàm setter áp dụng các quy tắc xác định nhiệt độ nào hợp lệ, bảo vệ tính toàn vẹn của đối tượng bất kể code bên ngoài cố gắng gán giá trị nào.

Tự làm thử

#include <stdio.h>
#include "temperature.h"

int main() {
    // Đọc dữ liệu đầu vào
    int initial, valid_temp, invalid_temp;
    scanf("%d", &initial);
    scanf("%d", &valid_temp);
    scanf("%d", &invalid_temp);
    
    // TODO: Tạo một Temperature với giá trị ban đầu
    
    // TODO: In ra nhiệt độ ban đầu
    // Định dạng: "Initial: {degrees}"
    
    // TODO: Thử đặt nhiệt độ không hợp lệ
    // In ra kết quả và cho thấy giá trị vẫn không đổi
    // Định dạng: "Set {invalid}: {0 or 1}"
    // Định dạng: "After invalid: {degrees}"
    
    // TODO: Đặt nhiệt độ hợp lệ
    // In ra kết quả thành công và giá trị đã cập nhật
    // Định dạng: "Set {valid}: {0 or 1}"
    // Định dạng: "After valid: {degrees}"
    
    // TODO: Giải phóng bộ nhớ và in ra "Freed"
    
    return 0;
}
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 C online