Patrón de Diseño Abstract Factory: El Kit de Creación de Familias 🚗
Imagina que estás programando el sistema de pedidos de un gran grupo automovilístico. Necesitas crear coches, pero tienes dos familias de vehículos muy diferentes: la gama “SEAT” (práctica y familiar) y la gama “CUPRA” (deportiva y de altas prestaciones).

El Patrón de Diseño Abstract Factory es como tener una “Fábrica de Fábricas” o un “Maestro Constructor de Temas”. Su función es permitirte crear familias de objetos relacionados o dependientes (como un motor, un chasis y unos asientos), garantizando que todos pertenezcan a la misma línea de diseño (o la familia SEAT o la familia CUPRA).
¿En qué Consiste?
Este patrón te permite trabajar con interfaces (contratos) sin conocer el nombre de las clases específicas.
Los Tres Roles Principales:
- Abstract Factory (La Receta General): Es una interfaz o clase abstracta, el contrato principal. Declara el conjunto de métodos que deben seguir todas las fábricas. Es la promesa de que “esta fábrica sabrá cómo hacer un Motor y un Asiento”. Ejemplo: La interfaz
CocheFactory
. - Concrete Factory (Las Fábricas Específicas): Son las implementaciones concretas de la Abstract Factory. Cada una crea productos de una familia específica.
SeatFactory
(Crea productos de la familia SEAT).CupraFactory
(Crea productos de la familia CUPRA).
- Abstract Product y Concrete Product (Los Componentes y sus Versiones): Son los objetos que se crean. El Abstract Product es la interfaz genérica del componente (
Motor
,Asiento
), y el Concrete Product es la versión específica.MotorSeat
yAsientoSeat
(Pertenecen a la familia SEAT).MotorCupra
yAsientoCupra
(Pertenecen a la familia CUPRA).
La Gran Ventaja: Intercambiabilidad Garantizada
Lo guapo del Abstract Factory es que si en tu código necesitas construir un coche completo, solo tienes que decidir al inicio qué Concrete Factory vas a usar (SeatFactory
o CupraFactory
). Todo lo que pidas después a esa fábrica estará garantizadamente en línea con esa familia, sin tener que cambiar el resto de tu código.
Ejemplo de la Vida Real: SEAT vs. CUPRA 🏎️
Imagina que quieres montar un coche:
Componente del Patrón | Ejemplo en Automoción |
---|---|
Abstract Factory | MarcaCocheFactory (Métodos: crearMotor() , crearAsiento() ) |
Concrete Factory | SeatFactory o CupraFactory |
Abstract Product | Motor y Asiento (Interfaces genéricas) |
Concrete Product | MotorSeat , AsientoCupra , MotorCupra , etc. |
Flujo de Trabajo
- Decisión Inicial: El cliente pide un coche CUPRA.
- Creación de la Fábrica: Tu código crea la Concrete Factory:
new CupraFactory()
. - Uso (Cliente): Para construir el coche, tu código (el cliente) solo usa los métodos de la interfaz
MarcaCocheFactory
:$motor = $fabrica->crearMotor();
$asiento = $fabrica->crearAsiento();
- Resultado: El código cliente recibe un MotorCupra y un AsientoCupra. Si mañana quiere un SEAT, solo cambia la línea de la creación de la fábrica (
new SeatFactory()
), y recibirá automáticamente el MotorSeat y el AsientoSeat, sin tocar el código de montaje. ¡Magic! 🧙♀️
Ejemplo de Código en PHP
Este es un ejemplo simplificado de cómo se vería la estructura en PHP, siguiendo el ejemplo de los coches.
1. Las Interfaces (Abstract Factory y Abstract Products)
<?php
// Abstract Products: Los componentes que queremos
interface Motor {
public function obtenerTipoMotor(): string;
}
interface Asiento {
public function obtenerMaterial(): string;
}
// Abstract Factory: El contrato para todas las fábricas
interface MarcaCocheFactory {
public function crearMotor(): Motor;
public function crearAsiento(): Asiento;
}
?>
2. Los Productos Concretos (Las Familias)
<?php
// Productos Concretos de la Familia SEAT
class MotorSeat implements Motor {
public function obtenerTipoMotor(): string {
return "Motor SEAT 1.0 TSI (Eficiente y económico)";
}
}
class AsientoSeat implements Asiento {
public function obtenerMaterial(): string {
return "Asiento SEAT (Tela con diseño práctico)";
}
}
// Productos Concretos de la Familia CUPRA
class MotorCupra implements Motor {
public function obtenerTipoMotor(): string {
return "Motor CUPRA 2.0 TSi (Alto rendimiento y deportivo)";
}
}
class AsientoCupra implements Asiento {
public function obtenerMaterial(): string {
return "Asiento CUPRA (Piel perforada y deportivo)";
}
}
3. Las Fábricas Concretas (Concrete Factories)
<?php
// Concrete Factory para la familia SEAT
class SeatFactory implements MarcaCocheFactory {
public function crearMotor(): Motor {
return new MotorSeat();
}
public function crearAsiento(): Asiento {
return new AsientoSeat();
}
}
// Concrete Factory para la familia CUPRA
class CupraFactory implements MarcaCocheFactory {
public function crearMotor(): Motor {
return new MotorCupra();
}
public function crearAsiento(): Asiento {
return new AsientoCupra();
}
}
4. El Código Cliente (El Montador)
El código cliente solo interactúa con las interfaces y no conoce los nombres de las clases concretas (MotorSeat, AsientoCupra, etc.).
<?php
// El código cliente que usa la fábrica para montar un coche
function montarCoche(MarcaCocheFactory $fabrica) {
$motor = $fabrica->crearMotor();
$asiento = $fabrica->crearAsiento();
echo "--- Montando Coche --- \n";
echo "Motor: " . $motor->obtenerTipoMotor() . "\n";
echo "Asiento: " . $asiento->obtenerMaterial() . "\n";
echo "------------------------ \n";
}
// Caso 1: Creamos un coche SEAT
$fabricaSeat = new SeatFactory();
montarCoche($fabricaSeat);
// Caso 2: Cambiamos a un coche CUPRA, ¡solo cambiando la fábrica!
$fabricaCupra = new CupraFactory();
montarCoche($fabricaCupra);
/*
Salida esperada:
--- Montando Coche ---
Motor: Motor SEAT 1.0 TSI (Eficiente y económico)
Asiento: Asiento SEAT (Tela con diseño práctico)
------------------------
--- Montando Coche ---
Motor: Motor CUPRA 2.0 TSi (Alto rendimiento y deportivo)
Asiento: Asiento CUPRA (Piel perforada y deportivo)
------------------------
*/
Ejercicio Práctico 🧠
Para que termines de entender la potencia del Abstract Factory, te propongo este ejercicio:
Tu tarea: Añadir una nueva familia al sistema de coches: la marca SKODA.
- Crea la clase MotorSkoda y AsientoSkoda. (Puedes describirlos como “Robusto y espacioso”).
- Asegúrate de que ambas implementen las interfaces Motor y Asiento.
- Crea la Concrete Factory llamada SkodaFactory que implemente MarcaCocheFactory.
En el código cliente, instancia la SkodaFactory y llama a la función montarCoche()
con ella.
Si consigues que tu código imprima la línea de SKODA sin modificar la función montarCoche()
, ¡habrás entendido perfectamente el patrón Abstract Factory!
EA, nos vemos en los bares! 🍺 saluditos