Menu
Coddy logo textTech

Паттерн Factory

Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 55 из 61.

Паттерн Factory централизует создание объектов в одной функции. Вместо того чтобы распределять malloc и код инициализации по всей программе, вы вызываете одну функцию, которая решает, что создать, и возвращает готовый к использованию объект.

Этот шаблон особенно эффективен в сочетании с полиморфизмом. factory может возвращать разные конкретные типы через общий указатель base, скрывая детали создания от вызывающего кода. Вызывающий код просто запрашивает «фигуру», а factory решает, создать ли круг, прямоугольник или что-то ещё.

Вот типичная реализация фабрики:

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;
    }
}

Фабрика принимает идентификатор (обычно enum) и использует оператор switch, чтобы определить, какой constructor вызвать. Она возвращает Shape* независимо от фактически созданного типа. Вызывающему коду не нужно знать о Circle или Rectangle. Он просто работает с базовым типом:

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // полиморфный вызов
free_shape(s);

Этот шаблон упрощает добавление новых типов: просто добавь новое значение enum и новый case в factory. Остальной код останется без изменений.

challenge icon

Задание

Легко

Давайте создадим Pet Factory: систему, которая создаёт разные типы питомцев с помощью одной factory function. Вместо того чтобы распределять логику создания по всему коду, вы централизуете её в одном месте, которое решает, какого питомца создать, основываясь на входном идентификаторе.

Вы организуете код в трёх файлах:

  • pet.h: Определите перечисление PetType со значениями PET_DOG, PET_CAT и PET_BIRD. Создайте базовую структуру Pet, содержащую указатель на function для speak (которая принимает const Pet* и ничего не возвращает). Объявите factory function create_pet, которая принимает PetType и возвращает Pet*, а также function free_pet для очистки.
  • pet.c: Определите три конкретные структуры питомцев — Dog, Cat и Bird, каждая из которых встраивает Pet в качестве своего первого member. Реализуйте function speak для каждого типа:
    • Dogs выводят: Woof!
    • Cats выводят: Meow!
    • Birds выводят: Tweet!
    Создайте constructor functions для каждого типа питомца, которые Allocate memory и связывают appropriate function speak. Затем реализуйте factory create_pet: используйте switch statement для PetType, чтобы вызвать correct constructor и вернуть результат как Pet*. Для invalid типов верните NULL. Реализуйте free_pet, чтобы освободить Allocate memory.
  • main.c: Считайте целое число, представляющее тип питомца (0 для dog, 1 для cat, 2 для bird). Используйте factory, чтобы создать appropriate питомца, вызовите его function speak полиморфно через указатель базового типа Pet*, затем освободите питомца.

Ваша программа получит один входной параметр: целое число, указывающее, какого питомца создать.

Пример вывода, когда входное значение равно 0:

Woof!

Пример вывода, когда входное значение равно 1:

Meow!

Пример вывода, когда входное значение равно 2:

Tweet!

Преимущество паттерна Factory заключается в том, что main.c не нужно знать о структурах Dog, Cat или Bird. Он работает только с базовым типом Pet. Добавление нового типа питомца в дальнейшем означает добавление нового значения перечисления и нового case в factory без изменения кода, использующего питомцев.

Попробуйте сами

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

int main(void) {
    int type;
    scanf("%d", &type);
    
    // TODO: Используйте фабрику, чтобы создать подходящего питомца
    // Подсказка: Приведите int к PetType
    
    // TODO: Вызовите функцию speak полиморфно через указатель Pet*
    
    // TODO: Освободите питомца
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C