Patrón Factory
Parte de la sección Programación Orientada a Objetos 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 malloc y el código de inicialización por todo tu programa, llamas 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 distintos tipos concretos mediante 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 construye un círculo, un rectángulo o alguna otra cosa.
Esta es una implementación típica de una fábrica:
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 recibe un identificador (normalmente un enum) y utiliza una sentencia switch para determinar a qué constructor llamar. Devuelve un Shape* independientemente del tipo real creado. La persona que llama no necesita conocer Circle ni 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 añadir nuevos tipos: solo tienes que añadir un nuevo valor de enumeración y un nuevo caso en la fábrica. El resto de tu código permanece sin cambios.
Desafío
FácilConstruyamos una Fábrica de mascotas: un sistema que crea distintos tipos de mascotas mediante una única función de fábrica. En lugar de dispersar la lógica de creación por todo tu código, la centralizarás en un solo lugar que decide qué tipo de mascota crear según un identificador de entrada.
Organizarás tu código en tres archivos:
pet.h: Define una enumeraciónPetTypecon 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_pet, que recibe unPetTypey devuelve unPet*, además de una funciónfree_petpara la limpieza.pet.c: Define tres estructuras concretas de mascotas,Dog,CatyBird, cada una incorporandoPetcomo 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: usa una sentencia switch sobrePetTypepara llamar al constructor correcto y devolver el resultado como unPet*. Para los 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). Usa la fábrica para crear la mascota correspondiente, llama a su funciónspeakpolimórficamente mediante el puntero basePet*y después libera la mascota.
Tu programa recibirá una entrada: un entero que indica qué mascota crear.
Salida de ejemplo cuando la entrada es 0:
Woof!Salida de ejemplo cuando la entrada es 1:
Meow!Salida de ejemplo cuando la entrada es 2:
Tweet!La ventaja 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 de enumeración y un nuevo caso en la fábrica, sin cambiar ningún código que use mascotas.
Pruébalo tú mismo
#include <stdio.h>
#include "pet.h"
int main(void) {
int type;
scanf("%d", &type);
// TODO: Usa la factory para crear el pet apropiado
// Pista: Haz cast del int a PetType
// TODO: Llama a la función speak polimórficamente a través del puntero Pet*
// TODO: Libera el pet
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
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írculoImplementación del rectánguloUso polimórficoContenedor de figurasPractica por tu cuenta: Compilador de C online