Menu
Coddy logo textTech

Patrón Factory

Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 55 de 61.

El patrón Factory centraliza la creación de objetos en una sola función. En lugar de dispersar el código de malloc e inicialización por todo su programa, usted llama a una función que decide qué crear y devuelve un objeto listo para usar.

Este patrón es especialmente potente cuando se combina con el polimorfismo. Una fábrica puede devolver diferentes tipos concretos a través de un puntero base común, ocultando los detalles de creación al llamador. El llamador simplemente solicita "una forma" y la fábrica decide si construir un círculo, un rectángulo o algo más.

Aquí hay una implementación típica de una fábrica (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;
    }
}

La fábrica toma un identificador (usualmente un enum) y utiliza una sentencia switch para determinar a qué constructor llamar. Devuelve un Shape* independientemente del tipo real creado. El llamador no necesita saber sobre Circle o Rectangle — simplemente trabaja con el tipo base:

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // llamada polimórfica
free_shape(s);

Este patrón facilita la adición de nuevos tipos: simplemente añade un nuevo valor de enum y un nuevo caso en la factory. El resto de tu código permanece sin cambios.

challenge icon

Desafío

Fácil

Vamos a construir una Pet Factory (Fábrica de Mascotas), un sistema que crea diferentes tipos de mascotas a través de una única función de fábrica. En lugar de dispersar la lógica de creación por todo el código, la centralizarás en un solo lugar que decide qué tipo de mascota crear basándose en un identificador de entrada.

Organizarás tu código en tres archivos:

  • pet.h: Define un enum PetType con los valores PET_DOG, PET_CAT y PET_BIRD. Crea una estructura base Pet que contenga un puntero a función para speak (que recibe un const Pet* y no devuelve nada). Declara la función de fábrica create_pet que recibe un PetType y devuelve un Pet*, además de una función free_pet para la limpieza de memoria.
  • pet.c: Define tres estructuras de mascotas concretas — Dog, Cat y Bird — cada una integrando Pet como su primer miembro. Implementa una función speak para cada tipo:
    • Los perros imprimen: Woof!
    • Los gatos imprimen: Meow!
    • Los pájaros imprimen: Tweet!
    Crea funciones constructoras para cada tipo de mascota que asignen memoria y vinculen la función speak correspondiente. Luego, implementa la fábrica create_pet: utiliza una sentencia switch sobre el PetType para llamar al constructor correcto y devolver el resultado como un Pet*. Para tipos no válidos, devuelve NULL. Implementa free_pet para liberar la memoria asignada.
  • main.c: Lee un entero que representa el tipo de mascota (0 para perro, 1 para gato, 2 para pájaro). Utiliza tu fábrica para crear la mascota adecuada, llama a su función speak de forma polimórfica a través del puntero base Pet* y luego libera la mascota.

Tu programa recibirá una entrada: un número entero que indica qué mascota crear.

Ejemplo de salida cuando la entrada es 0:

Woof!

Ejemplo de salida cuando la entrada es 1:

Meow!

Ejemplo de salida cuando la entrada es 2:

Tweet!

La belleza del patrón Factory es que main.c no necesita conocer las estructuras Dog, Cat o Bird; solo trabaja con el tipo base Pet. Añadir un nuevo tipo de mascota más adelante significa agregar un nuevo valor al enum y un nuevo caso en la fábrica, sin cambiar el código que utiliza las mascotas.

Hoja de referencia

El patrón Factory centraliza la creación de objetos en una sola función, ocultando los detalles de creación al llamador.

Una función factory toma un identificador (típicamente un enum) y utiliza una sentencia switch para determinar a qué constructor llamar, devolviendo un puntero de tipo base:

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

El llamador trabaja solo con el tipo base, permitiendo un comportamiento polimórfico:

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // polymorphic call
free_shape(s);

Beneficios: Añadir nuevos tipos solo requiere agregar un nuevo valor al enum y un caso al switch, sin cambiar el código existente que utiliza la factory.

Pruébalo tú mismo

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

int main(void) {
    int type;
    scanf("%d", &type);
    
    // TODO: Usa la fábrica para crear la mascota apropiada
    // Sugerencia: Convierte el int a PetType
    
    // TODO: Llama a la función speak de forma polimórfica a través del puntero Pet*
    
    // TODO: Libera la mascota
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming