Menu
CoddyTech

Mẫu Factory

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 55 trên 61.

Mẫu Factory tập trung việc tạo đối tượng vào một hàm duy nhất. Thay vì rải malloc và code khởi tạo khắp chương trình, bạn gọi một hàm để quyết định cần tạo gì và trả về một đối tượng sẵn sàng sử dụng.

Mẫu này đặc biệt hữu ích khi kết hợp với tính đa hình. Một hàm tạo có thể trả về các kiểu cụ thể khác nhau thông qua một con trỏ cơ sở chung, che giấu chi tiết khởi tạo với bên gọi. Bên gọi chỉ cần yêu cầu “một hình dạng”, còn hàm tạo sẽ quyết định tạo hình tròn, hình chữ nhật hay hình dạng khác.

Đây là cách triển khai factory điển hình:

typedef enum {
    SHAPE_CIRCLE,
    SHAPE_RECTANGLE
} ShapeType;

Shape* create_shape(ShapeType type) {
    switch (type) {
        case SHAPE_CIRCLE:
            return (Shape*)create_circle(5.0);
        case SHAPE_RECTANGLE:
            return (Shape*)create_rectangle(4.0, 3.0);
        default:
            return NULL;
    }
}

Hàm factory nhận một mã định danh (thường là enum) và dùng câu lệnh switch để xác định cần gọi hàm khởi tạo nào. Hàm trả về một Shape* bất kể kiểu thực tế được tạo ra là gì. Bên gọi không cần biết về Circle hay Rectangle. Bên gọi chỉ cần làm việc với kiểu cơ sở:

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // lời gọi đa hình
free_shape(s);

Mẫu này giúp bạn dễ dàng thêm kiểu mới: chỉ cần thêm một giá trị enum mới và một nhánh case mới trong hàm factory. Phần còn lại của code vẫn giữ nguyên.

challenge icon

Thử thách

Dễ

Hãy xây dựng một nhà máy thú cưng: một hệ thống tạo ra nhiều loại thú cưng thông qua một hàm nhà máy (factory function). Thay vì rải rác logic tạo thú cưng khắp đoạn code, bạn sẽ tập trung logic đó vào một nơi để quyết định cần tạo loại thú cưng nào dựa trên mã định danh đầu vào.

Bạn sẽ sắp xếp đoạn code trong ba tệp:

  • pet.h: Định nghĩa một enum PetType với các giá trị PET_DOG, PET_CAT và PET_BIRD. Tạo một cấu trúc Pet cơ sở chứa con trỏ hàm cho speak (hàm này nhận một const Pet* và không trả về giá trị nào). Khai báo hàm nhà máy create_pet nhận một PetType và trả về một Pet*, cùng với hàm free_pet để giải phóng bộ nhớ.
  • pet.c: Định nghĩa ba cấu trúc thú cưng cụ thể là Dog, Cat và Bird, mỗi cấu trúc đều có Pet làm thành viên đầu tiên. Cài đặt một hàm phát tiếng kêu cho mỗi loại:
    • Chó in ra: Woof!
    • Mèo in ra: Meow!
    • Chim in ra: Tweet!
    Tạo hàm khởi tạo cho mỗi loại thú cưng để cấp phát bộ nhớ và gắn hàm phát tiếng kêu phù hợp. Sau đó, cài đặt hàm nhà máy create_pet: dùng câu lệnh switch với PetType để gọi hàm khởi tạo thích hợp và trả về kết quả dưới dạng Pet*. Với các kiểu không hợp lệ, trả về NULL. Cài đặt free_pet để giải phóng bộ nhớ đã cấp phát.
  • main.c: Đọc một số nguyên biểu thị loại thú cưng (0 là chó, 1 là mèo, 2 là chim). Dùng hàm nhà máy để tạo thú cưng phù hợp, gọi hàm speak theo cách đa hình thông qua con trỏ Pet* cơ sở, rồi giải phóng thú cưng.

Chương trình của bạn sẽ nhận một đầu vào: số nguyên cho biết cần tạo loại thú cưng nào.

Đầu ra mẫu khi đầu vào là 0:

Woof!

Đầu ra mẫu khi đầu vào là 1:

Meow!

Đầu ra mẫu khi đầu vào là 2:

Tweet!

Điểm hay của mẫu nhà máy là main.c không cần biết về các cấu trúc Dog, Cat hay Bird. Đoạn code chỉ làm việc với kiểu Pet cơ sở. Nếu sau này thêm một loại thú cưng mới, bạn chỉ cần thêm một giá trị enum và một nhánh case mới trong hàm nhà máy, mà không cần thay đổi bất kỳ đoạn code nào đang sử dụng thú cưng.

Tự làm thử

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

int main(void) {
    int type;
    scanf("%d", &type);
    
    // TODO: Dùng factory để tạo thú cưng phù hợp
    // Gợi ý: Ép kiểu int sang PetType
    
    // TODO: Gọi hàm (function) speak theo cách đa hình thông qua con trỏ Pet*
    
    // TODO: Giải phóng bộ nhớ của thú cưng
    
    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