Patrón Factory Method

Patrón Factory Method

El herrero que forja héroes ⚔️🔥

💾 Continuamos nuestra serie de Patrones de Diseño explicados con ejemplos (un poco frikis) 👾

En esta entrega nos adentramos en la forja del código, donde los objetos no nacen por arte de magia, sino gracias al sabio Herrero de la Factoría.

⚙️ El problema: cuando tu código fabrica demasiado

Imagina que estás creando un juego de rol y necesitas generar distintos tipos de héroes:

  • un Guerrero para el combate cuerpo a cuerpo,
  • un Arquero para los ataques a distancia,
  • y un Mago para lanzar hechizos arcanos.

Podrías crear cada uno directamente con new… pero si el código empieza a decidir cómo crear cada héroe, terminarás con una mazmorra de if y switch.


💀 Ejemplo erróneo

<?php

class Heroe {
    public $nombre;
    public $arma;

    public function __construct($nombre, $arma) {
        $this->nombre = $nombre;
        $this->arma = $arma;
    }

    public function atacar() {
        echo "{$this->nombre} ataca con {$this->arma}!\n";
    }
}

class Juego {
    public function crearHeroe($tipo) {
        if ($tipo === "guerrero") {
            return new Heroe("Guerrero", "espada");
        } elseif ($tipo === "arquero") {
            return new Heroe("Arquero", "arco");
        } elseif ($tipo === "mago") {
            return new Heroe("Mago", "hechizo de fuego");
        }
    }
}

$juego = new Juego();
$heroe = $juego->crearHeroe("mago");
$heroe->atacar();

👉 Problema:
Si mañana quieres añadir un Paladín, tendrás que editar Juego, rompiendo el principio de abierto/cerrado.
El herrero está haciendo todo el trabajo, y eso no escala ⚒️

🧠 La solución: delega la forja a cada tipo de taller
El Patrón Factory Method nos enseña a dejar que cada subclase decida cómo fabricar su héroe.
El código principal no necesita saber los detalles de la creación.

✅ Ejemplo correcto con Factory Method

<?php

interface Heroe {
    public function atacar();
}

class Guerrero implements Heroe {
    public function atacar() {
        echo "⚔️ El Guerrero golpea con su espada!\n";
    }
}

class Arquero implements Heroe {
    public function atacar() {
        echo "🏹 El Arquero dispara una flecha!\n";
    }
}

class Mago implements Heroe {
    public function atacar() {
        echo "🔥 El Mago lanza un hechizo de fuego!\n";
    }
}

// --- La fábrica base ---
abstract class FabricaDeHeroes {
    abstract public function crearHeroe(): Heroe;

    public function prepararHeroe() {
        $heroe = $this->crearHeroe();
        echo "✨ Se ha forjado un nuevo héroe...\n";
        return $heroe;
    }
}

// --- Fábricas concretas ---
class FabricaGuerrero extends FabricaDeHeroes {
    public function crearHeroe(): Heroe {
        return new Guerrero();
    }
}

class FabricaArquero extends FabricaDeHeroes {
    public function crearHeroe(): Heroe {
        return new Arquero();
    }
}

class FabricaMago extends FabricaDeHeroes {
    public function crearHeroe(): Heroe {
        return new Mago();
    }
}

// --- Cliente ---
$fabricas = [
    new FabricaGuerrero(),
    new FabricaArquero(),
    new FabricaMago(),
];

foreach ($fabricas as $fabrica) {
    $heroe = $fabrica->prepararHeroe();
    $heroe->atacar();
}

⚔️ Resultado

✨ Se ha forjado un nuevo héroe...
⚔️ El Guerrero golpea con su espada!
✨ Se ha forjado un nuevo héroe...
🏹 El Arquero dispara una flecha!
✨ Se ha forjado un nuevo héroe...
🔥 El Mago lanza un hechizo de fuego!

🧩 Qué conseguimos
Separación de responsabilidades – el juego no decide cómo se crean los héroes.
Extensibilidad – puedes añadir nuevas fábricas sin tocar el código existente.
Código más limpio y reutilizable – el herrero trabaja con disciplina OOP 😎

🧙‍♂️ En resumen
El Patrón Factory Method es como tener un maestro herrero en tu proyecto: tú solo le pides el héroe que necesitas, y él se encarga de forjarlo sin romper nada.

Eso ha sido todo por hoy.
Nos vemos en el próximo patrón... o en la próxima frikada que se me ocurra para explicarlo ⚒️🔥