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 Decorator es un patrón de diseño estructural que te permite añadir dinámicamente nuevos comportamientos a los objetos envolviéndolos en objetos envoltorio 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, después añades extras como leche, azúcar o crema batida.

Cada adición envuelve el café original y añade información 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 el doble de leche? Solo envuélvelo dos veces.

challenge icon

Desafío

Fácil

Construyamos un sistema de pedidos de pizza usando el Patrón Decorador. Comenzarás con una pizza básica y añadirás ingredientes dinámicamente: cada ingrediente envuelve la pizza y añade elementos a su descripción y precio, igual que en el ejemplo del café de la lección.

Organizarás tu código en cuatro archivos:

  • Pizza.php: Define una interfaz Pizza que establece el contrato para todas las pizzas y los ingredientes. Debe tener dos métodos: getDescription(): string y getPrice(): float.
  • BasePizza.php: Incluye la interfaz Pizza y crea una clase MargheritaPizza que la implementa. 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 implementan. 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 que se deben añadir (por ejemplo, "cheese,pepperoni" o "mushroom,cheese,cheese").

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

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

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

    [description] = $[price]

    Da formato al precio con dos decimales.

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

Pruébalo tú mismo

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

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

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

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

// TODO: Imprimir el resultado en 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

Practica por tu cuenta: Compilador de PHP online