Menu
Coddy logo textTech

Patrón Decorator

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 77 de 91.

El Patrón Decorador es un patrón de diseño estructural que permite añadir nuevos comportamientos a los objetos de forma dinámica envolviéndolos en objetos envoltorios especiales llamados decoradores. A diferencia de la herencia, que añade comportamiento en tiempo de compilación, los decoradores añaden comportamiento en tiempo de ejecución.

Imagina una cafetería. Empiezas con un café básico y luego añades extras como leche, azúcar o crema batida.

Cada adición envuelve al café original y se suma a su descripción y costo. La idea clave es que tanto el café base como los decoradores comparten la misma interfaz.

<?php
interface Coffee {
    public function getDescription(): string;
    public function getCost(): float;
}

class SimpleCoffee implements Coffee {
    public function getDescription(): string {
        return "Simple Coffee";
    }
    
    public function getCost(): float {
        return 2.00;
    }
}

Los decoradores implementan la misma interfaz y envuelven otro objeto Coffee:

<?php
class MilkDecorator implements Coffee {
    public function __construct(private Coffee $coffee) {}
    
    public function getDescription(): string {
        return $this->coffee->getDescription() . ", Milk";
    }
    
    public function getCost(): float {
        return $this->coffee->getCost() + 0.50;
    }
}

class SugarDecorator implements Coffee {
    public function __construct(private Coffee $coffee) {}
    
    public function getDescription(): string {
        return $this->coffee->getDescription() . ", Sugar";
    }
    
    public function getCost(): float {
        return $this->coffee->getCost() + 0.25;
    }
}

$coffee = new SimpleCoffee();
$coffee = new MilkDecorator($coffee);
$coffee = new SugarDecorator($coffee);

echo $coffee->getDescription() . " = $" . $coffee->getCost();

Salida:

Simple Coffee, Milk, Sugar = $2.75

Cada decorador envuelve al objeto anterior, formando una cadena. El patrón permite combinar comportamientos en cualquier orden y cantidad sin crear una clase para cada combinación posible. ¿Necesitas leche doble? Simplemente envuélvelo dos veces.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de pedido de pizzas utilizando el Patrón Decorator. Comenzarás con una pizza básica y añadirás ingredientes dinámicamente; cada ingrediente envuelve la pizza y se suma a su descripción y precio, tal como el ejemplo del café de la lección.

Organizarás tu código en cuatro archivos:

  • Pizza.php — Define una interfaz Pizza que establezca el contrato para todas las pizzas e ingredientes. Debe tener dos métodos: getDescription(): string y getPrice(): float.
  • BasePizza.php — Incluye la interfaz Pizza y crea una clase MargheritaPizza que la implemente. Esta es tu pizza base con una descripción de "Margherita" y un precio de 8.00.
  • Toppings.php — Incluye la interfaz Pizza y crea tres clases decoradoras que la implementen. Cada decorador envuelve un objeto Pizza (acéptalo en el constructor) y mejora tanto la descripción como el precio:
    • CheeseTopping — Añade ", Extra Cheese" a la descripción y 1.50 al precio
    • PepperoniTopping — Añade ", Pepperoni" a la descripción y 2.00 al precio
    • MushroomTopping — Añade ", Mushrooms" a la descripción y 1.25 al precio
  • main.php — Incluye los archivos BasePizza y Toppings. Recibirás una entrada: una lista de ingredientes separados por comas para añadir (por ejemplo, "cheese,pepperoni" o "mushroom,cheese,cheese").

    Comienza con una MargheritaPizza. Para cada ingrediente en la entrada, envuelve tu pizza con el decorador apropiado:

    • "cheese" envuelve con CheeseTopping
    • "pepperoni" envuelve con PepperoniTopping
    • "mushroom" envuelve con MushroomTopping

    Después de aplicar todos los ingredientes, imprime la descripción y el precio final de la pizza en este formato:

    [description] = $[price]

    Formatea el precio con dos decimales.

Observa cómo el mismo ingrediente se puede aplicar varias veces: pedir queso doble simplemente significa envolver con CheeseTopping dos veces. ¡Esta flexibilidad es el poder del Patrón Decorator!

Pruébalo tú mismo

<?php
require_once 'BasePizza.php';
require_once 'Toppings.php';

// Leer la entrada - lista de ingredientes separados por comas
$input = trim(fgets(STDIN));
$toppings = explode(',', $input);

// Comenzar con una MargheritaPizza base
$pizza = new MargheritaPizza();

// TODO: Recorrer cada ingrediente y envolver la pizza con el decorador adecuado
// - "cheese" -> envolver con CheeseTopping
// - "pepperoni" -> envolver con PepperoniTopping
// - "mushroom" -> envolver con MushroomTopping

// TODO: Imprimir el resultado en el formato: [description] = $[price]
// Formatear el precio a 2 decimales usando number_format()

?>
quiz iconPonte a prueba

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