Patrón de Diseño Builder: El Maestro Constructor Personalizado 🍔
Imagina que estás en un McDonald’s y quieres pedir una hamburguesa. Pero no cualquier hamburguesa, sino TU hamburguesa perfecta: pan integral, doble carne, sin pepinillos, extra queso, salsa barbacoa, lechuga iceberg y tomate fresco.

El Patrón de Diseño Builder es como ese empleado experto que va construyendo tu hamburguesa paso a paso, ingrediente por ingrediente, hasta crear exactamente lo que pediste. Su función es permitirte construir objetos complejos de forma gradual y controlada, donde puedes elegir qué partes incluir y cuáles no.
¿En qué Consiste?
Este patrón te permite crear objetos complejos paso a paso, especificando solo las partes que necesitas, sin tener constructores gigantes con mil parámetros.
Los Cuatro Roles Principales:
-
Product (El Producto Final): Es el objeto complejo que estás construyendo. Ejemplo: La
Hamburguesa
terminada. -
Builder (La Interfaz del Constructor): Es el contrato que define qué partes se pueden construir. Es la promesa de que “este constructor sabrá cómo añadir pan, carne, verduras, etc.”. Ejemplo: La interfaz
HamburguesaBuilder
. -
ConcreteBuilder (Los Constructores Específicos): Son las implementaciones concretas del Builder. Cada una sabe cómo construir una variante específica del producto.
BigMacBuilder
(Sabe construir una Big Mac).VeggieBuilder
(Sabe construir una hamburguesa vegana).
-
Director (El Maestro de Ceremonias): Es opcional, pero muy útil. Conoce las recetas (secuencias de construcción) para crear productos populares. Ejemplo: El
ChefHamburguesas
que sabe los pasos para hacer una Big Mac clásica.
La Gran Ventaja: Construcción Flexible y Legible
Lo guapo del Builder es que puedes construir el mismo tipo de objeto de mil maneras diferentes. ¿Quieres una hamburguesa solo con pan y carne? Perfect. ¿Quieres una con todos los ingredientes del universo? También. Y lo más importante: tu código queda súper legible y fácil de entender.
Ejemplo de la Vida Real: McDonald’s vs. Burger King 🍟
Imagina que programas el sistema de pedidos de una cadena de hamburguesas:
Componente del Patrón | Ejemplo en Hamburguesas |
---|---|
Product | Hamburguesa (El producto final) |
Builder | HamburguesaBuilder (Métodos: agregarPan() , agregarCarne() , agregarQueso() ) |
ConcreteBuilder | BigMacBuilder , WhopperBuilder , VeggieBuilder |
Director | ChefHamburguesas (Conoce las recetas clásicas) |
Flujo de Trabajo
- Elección del Constructor: El cliente decide qué tipo de hamburguesa quiere:
new BigMacBuilder()
. - Construcción Paso a Paso: Tu código va añadiendo ingredientes:
$builder->agregarPan('sésamo')
$builder->agregarCarne('vacuno', 2)
$builder->agregarQueso('cheddar')
- Obtención del Resultado: Al final:
$hamburguesa = $builder->build()
- Flexibilidad Total: Si mañana quieres una Whopper, solo cambias el builder (
new WhopperBuilder()
), ¡pero el proceso de construcción es igual!
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 las hamburguesas.
1. El Producto (Product)
<?php
class Hamburguesa {
private string $pan = '';
private array $carnes = [];
private array $verduras = [];
private array $salsas = [];
private array $extras = [];
public function setPan(string $pan): void {
$this->pan = $pan;
}
public function addCarne(string $tipo, int $cantidad = 1): void {
for ($i = 0; $i < $cantidad; $i++) {
$this->carnes[] = $tipo;
}
}
public function addVerdura(string $verdura): void {
$this->verduras[] = $verdura;
}
public function addSalsa(string $salsa): void {
$this->salsas[] = $salsa;
}
public function addExtra(string $extra): void {
$this->extras[] = $extra;
}
public function mostrar(): string {
$descripcion = "🍔 HAMBURGUESA PERSONALIZADA 🍔\n";
$descripcion .= "Pan: " . ($this->pan ?: 'Sin especificar') . "\n";
$descripcion .= "Carnes: " . (empty($this->carnes) ? 'Ninguna' : implode(', ', $this->carnes)) . "\n";
$descripcion .= "Verduras: " . (empty($this->verduras) ? 'Ninguna' : implode(', ', $this->verduras)) . "\n";
$descripcion .= "Salsas: " . (empty($this->salsas) ? 'Ninguna' : implode(', ', $this->salsas)) . "\n";
$descripcion .= "Extras: " . (empty($this->extras) ? 'Ninguno' : implode(', ', $this->extras)) . "\n";
return $descripcion;
}
}
?>
2. La Interfaz Builder (Abstract Builder)
<?php
interface HamburguesaBuilder {
public function reset(): void;
public function agregarPan(string $tipo): self;
public function agregarCarne(string $tipo, int $cantidad = 1): self;
public function agregarVerdura(string $verdura): self;
public function agregarSalsa(string $salsa): self;
public function agregarExtra(string $extra): self;
public function build(): Hamburguesa;
}
?>
3. Los Constructores Concretos (Concrete Builders)
<?php
class BigMacBuilder implements HamburguesaBuilder {
private Hamburguesa $hamburguesa;
public function __construct() {
$this->reset();
}
public function reset(): void {
$this->hamburguesa = new Hamburguesa();
}
public function agregarPan(string $tipo): self {
$this->hamburguesa->setPan($tipo);
return $this;
}
public function agregarCarne(string $tipo, int $cantidad = 1): self {
$this->hamburguesa->addCarne($tipo, $cantidad);
return $this;
}
public function agregarVerdura(string $verdura): self {
$this->hamburguesa->addVerdura($verdura);
return $this;
}
public function agregarSalsa(string $salsa): self {
$this->hamburguesa->addSalsa($salsa);
return $this;
}
public function agregarExtra(string $extra): self {
$this->hamburguesa->addExtra($extra);
return $this;
}
public function build(): Hamburguesa {
$resultado = $this->hamburguesa;
$this->reset(); // Preparamos para la siguiente hamburguesa
return $resultado;
}
}
class VeggieBuilder implements HamburguesaBuilder {
private Hamburguesa $hamburguesa;
public function __construct() {
$this->reset();
}
public function reset(): void {
$this->hamburguesa = new Hamburguesa();
}
public function agregarPan(string $tipo): self {
$this->hamburguesa->setPan($tipo);
return $this;
}
public function agregarCarne(string $tipo, int $cantidad = 1): self {
// En la versión veggie, "carne" sería proteína vegetal
$this->hamburguesa->addCarne("Proteína vegetal ({$tipo})", $cantidad);
return $this;
}
public function agregarVerdura(string $verdura): self {
$this->hamburguesa->addVerdura($verdura);
return $this;
}
public function agregarSalsa(string $salsa): self {
$this->hamburguesa->addSalsa($salsa);
return $this;
}
public function agregarExtra(string $extra): self {
$this->hamburguesa->addExtra($extra);
return $this;
}
public function build(): Hamburguesa {
$resultado = $this->hamburguesa;
$this->reset();
return $resultado;
}
}
?>
4. El Director (Opcional pero Útil)
<?php
class ChefHamburguesas {
public function hacerBigMacClasica(HamburguesaBuilder $builder): Hamburguesa {
return $builder
->agregarPan('sésamo')
->agregarCarne('vacuno', 2)
->agregarVerdura('lechuga')
->agregarVerdura('cebolla')
->agregarVerdura('pepinillos')
->agregarSalsa('Big Mac sauce')
->agregarExtra('queso cheddar')
->build();
}
public function hacerVeggieSuprema(HamburguesaBuilder $builder): Hamburguesa {
return $builder
->agregarPan('integral')
->agregarCarne('soja')
->agregarVerdura('lechuga')
->agregarVerdura('tomate')
->agregarVerdura('aguacate')
->agregarVerdura('cebolla morada')
->agregarSalsa('mostaza')
->agregarSalsa('mayonesa vegana')
->agregarExtra('queso vegano')
->build();
}
}
?>
5. El Código Cliente (El Que Hace los Pedidos)
<?php
// Forma 1: Construcción manual (máxima flexibilidad)
echo "=== PEDIDO PERSONALIZADO ===\n";
$builder = new BigMacBuilder();
$miHamburguesa = $builder
->agregarPan('brioche')
->agregarCarne('vacuno', 1)
->agregarVerdura('lechuga')
->agregarVerdura('tomate')
->agregarSalsa('ketchup')
->agregarExtra('bacon')
->agregarExtra('queso gouda')
->build();
echo $miHamburguesa->mostrar();
// Forma 2: Usando el Director (recetas pre-definidas)
echo "\n=== PEDIDOS CON RECETAS CLÁSICAS ===\n";
$chef = new ChefHamburguesas();
// Big Mac clásica
$builderBigMac = new BigMacBuilder();
$bigMac = $chef->hacerBigMacClasica($builderBigMac);
echo $bigMac->mostrar();
// Veggie suprema
$builderVeggie = new VeggieBuilder();
$veggieSuprema = $chef->hacerVeggieSuprema($builderVeggie);
echo $veggieSuprema->mostrar();
/*
Salida esperada:
=== PEDIDO PERSONALIZADO ===
🍔 HAMBURGUESA PERSONALIZADA 🍔
Pan: brioche
Carnes: vacuno
Verduras: lechuga, tomate
Salsas: ketchup
Extras: bacon, queso gouda
=== PEDIDOS CON RECETAS CLÁSICAS ===
🍔 HAMBURGUESA PERSONALIZADA 🍔
Pan: sésamo
Carnes: vacuno, vacuno
Verduras: lechuga, cebolla, pepinillos
Salsas: Big Mac sauce
Extras: queso cheddar
🍔 HAMBURGUESA PERSONALIZADA 🍔
Pan: integral
Carnes: Proteína vegetal (soja)
Verduras: lechuga, tomate, aguacate, cebolla morada
Salsas: mostaza, mayonesa vegana
Extras: queso vegano
*/
?>
¿Cuándo Usar el Patrón Builder? 🤔
El Builder es perfecto cuando:
- Objetos complejos: Tienes que crear objetos con muchas propiedades opcionales
- Constructores gigantes: Te cansas de ver constructores con 10+ parámetros
- Flexibilidad: Quieres poder crear el mismo objeto de diferentes maneras
- Legibilidad: Prefieres código que se lea como una receta paso a paso
¡Cuidado! No uses Builder para objetos simples. Si tu objeto solo tiene 2-3 propiedades, es overkill.
Ejercicio Práctico 🧠
Para que termines de entender la potencia del Builder, te propongo este ejercicio:
Tu tarea: Añadir una nueva receta al ChefHamburguesas
: la “Hamburguesa Fitness”.
- Debe usar pan integral
- Proteína: pechuga de pollo a la plancha
- Verduras: lechuga, tomate, pepino
- Sin salsas grasas (solo mostaza)
- Extra: aguacate
Crea el método hacerHamburguesaFitness()
en la clase ChefHamburguesas
y pruébalo con cualquiera de los builders.
Si consigues que imprima tu hamburguesa fitness sin tocar las clases Hamburguesa
o los builders, dominas el patrón builder.
EA, nos vemos en los bares! 🍺 saluditos