Factory Method ¿Qué es? 🧐
El patrón de diseño Factory Method es un patrón de diseño creacional. Esto quiere decir que nos va a ayudar a crear objetos sin tener que escribir directamente la lógica de creación en varios lugares del código.

Imagínate que quieres fabricar coches Cupra desde varias partes del código. Esto se puede volver un auténtico coñazo de mantener, pero con un Factory Method se soluciona todo. 🚀
Pero cuidadito shavá, no es solo meter todo en una clase y ya está. El Factory Method es más elegante: defines una “fábrica abstracta” que dice “oye, aquí se van a crear coches, pero no sé cuáles exactamente”. Luego tienes fábricas específicas que heredan de esta y cada una sabe crear su rollo.
Por ejemplo, tienes una CupraFactory
abstracta que dice “aquí se crean coches Cupra” pero no especifica cuáles. Luego tienes CupraLeonFactory
que hereda de la anterior y, cuando le pides un coche, te fabrica un León flamante. También tienes CupraFormentorFactory
que hace lo mismo, pero con Formentors.
Lo guapo de esto es que si mañana Cupra saca un modelo nuevo, solo creas una nueva fábrica (CupraAtecaFactory
por ejemplo) sin tocar ni una línea del código que ya tienes. Tu código que pide coches no tiene ni idea de si está pidiendo un León o un Formentor, solo sabe que está pidiendo a una fábrica Cupra y le van a dar un coche Cupra.
Pues esto es el Factory Method: cada fábrica sabe crear su producto específico, pero todas comparten la misma interfaz para pedírselo.
Este POST no lo patrocina Cupra.
¿Qué problema resuelve Factory Method? 🤔
Bueno, el problema que resuelve en realidad lo hemos dejado claro en el anterior punto.
Imagínate que Cupra va sacando varios modelos de coche y nosotros únicamente tenemos la clase Cupra
para hacer un new Cupra
y dentro toda la lógica mezclada de alguna forma. Pues con Factory Method nos ahorramos esto, ya que al extender la fábrica abstracta podemos hacer un new
de cada modelo sin mezclar lógica de nada.
Imagínate que tienes este código:
// index.php
$modelo = $_GET['modelo'] ?? 'leon';
switch ($modelo) {
case 'leon':
$coche = new CupraLeon();
break;
case 'formentor':
$coche = new CupraFormentor();
break;
case 'ateca':
$coche = new CupraAteca();
break;
default:
throw new Exception("Modelo desconocido");
}
$coche->arrancar();
Ya tendríamos esto:
// Interfaz y productos (ya los teníamos)
interface CupraCoche
{
public function arrancar(): string;
}
class CupraLeon implements CupraCoche
{
public function arrancar(): string
{
return "León: ¡Brrrum! 300 CV";
}
}
class CupraFormentor implements CupraCoche
{
public function arrancar(): string
{
return "Formentor: ¡Zas! 310 CV";
}
}
class CupraAteca implements CupraCoche
{
public function arrancar(): string
{
return "Ateca: ¡Prrr! 300 CV";
}
}
Podríamos implementar una fábrica abstracta y sus fábricas concretas:
abstract class CupraFactory
{
abstract public function crearCoche(): CupraCoche;
}
class CupraLeonFactory extends CupraFactory
{
public function crearCoche(): CupraCoche
{
return new CupraLeon();
}
}
class CupraFormentorFactory extends CupraFactory
{
public function crearCoche(): CupraCoche
{
return new CupraFormentor();
}
}
class CupraAtecaFactory extends CupraFactory
{
public function crearCoche(): CupraCoche
{
return new CupraAteca();
}
}
Ahora nos podríamos cargar el `switch` y dejarlo más limpio. ¡Mira qué guapo pavo! ✨
// index.php
$modelo = $_GET['modelo'] ?? 'leon';
// Fábrica "mapeada" (array asoc.)
$fabricas = [
'leon' => new CupraLeonFactory(),
'formentor' => new CupraFormentorFactory(),
'ateca' => new CupraAtecaFactory(),
];
if (!isset($fabricas[$modelo])) {
throw new Exception("Modelo desconocido");
}
$coche = $fabricas[$modelo]->crearCoche(); // ¡Una sola línea! 🤯
echo $coche->arrancar();
Si aparece un nuevo modelo de coche, pues es fácil: añades otro CupraModelo
, haces su fábrica, lo añades al array y ya está, listo.
¡Ea! Nos vemos en los bares. 🍻