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.
Desafío
FácilVamos 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 enumPetTypecon los valoresPET_DOG,PET_CATyPET_BIRD. Crea una estructura basePetque contenga un puntero a función paraspeak(que recibe unconst Pet*y no devuelve nada). Declara la función de fábricacreate_petque recibe unPetTypey devuelve unPet*, además de una funciónfree_petpara la limpieza de memoria.pet.c: Define tres estructuras de mascotas concretas —Dog,CatyBird— cada una integrandoPetcomo su primer miembro. Implementa una función speak para cada tipo:- Los perros imprimen:
Woof! - Los gatos imprimen:
Meow! - Los pájaros imprimen:
Tweet!
create_pet: utiliza una sentencia switch sobre elPetTypepara llamar al constructor correcto y devolver el resultado como unPet*. Para tipos no válidos, devuelveNULL. Implementafree_petpara liberar la memoria asignada.- Los perros imprimen:
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ónspeakde forma polimórfica a través del puntero basePet*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;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Fundamentos de programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculo