Sobes.tech
Middle

¿Cómo funciona un decorador en PHP?

sobes.tech AI

Respuesta de la IA

El patrón "Decorador" añade dinámicamente un nuevo comportamiento a un objeto existente envolviéndolo en otro objeto, llamado decorador.

  • Componentes:

    • Interfaz (Component): Declara métodos comunes para el objeto original y sus decoradores.
    • Componente Concreto (Concrete Component): Objeto principal que se desea decorar.
    • Decorador Base (Decorator): Clase abstracta o interfaz que contiene una referencia a un objeto de la interfaz (Component) y implementa sus métodos, generalmente delegando la llamada a ese objeto.
    • Decoradores Concretos (Concrete Decorators): Implementan nuevas funcionalidades, complementando o modificando el comportamiento del componente base.
  • Principio de funcionamiento:

    • El decorador contiene una referencia al objeto que decora (composición).
    • El decorador tiene la misma interfaz que el objeto decorado.
    • Al llamar a un método en el decorador, este realiza lógica adicional antes o después de llamar al método correspondiente en el objeto decorado, o lo reemplaza completamente (aunque esto último no es un uso típico).
  • Ventajas:

    • Permite agregar funcionalidad a los objetos en tiempo de ejecución, no en forma estática mediante herencia.
    • Evita la "explosión" de la jerarquía de clases al combinar múltiples comportamientos diferentes.
    • Permite crear combinaciones flexibles de comportamientos.
  • Ejemplo:

<?php

// Interfaz del componente
interface Coffee {
    public function getCost(): float;
    public function getDescription(): string;
}

// Componente concreto
class SimpleCoffee implements Coffee {
    public function getCost(): float {
        return 5.0;
    }

    public function getDescription(): string {
        return "Café simple";
    }
}

// Decorador base
abstract class CoffeeDecorator implements Coffee {
    protected Coffee $coffee;

    public function __construct(Coffee $coffee) {
        $this->coffee = $coffee;
    }

    public function getCost(): float {
        return $this->coffee->getCost();
    }

    public function getDescription(): string {
        return $this->coffee->getDescription();
    }
}

// Decorador concreto: Añadir leche
class MilkDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 2.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", con leche";
    }
}

// Decorador concreto: Añadir azúcar
class SugarDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 1.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", con azúcar";
    }
}

// Uso:
// Crear un café simple
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . " - " . $coffee->getCost() . "\n"; // Café simple - 5

// Añadir leche
$coffeeWithMilk = new MilkDecorator($coffee);
echo $coffeeWithMilk->getDescription() . " - " . $coffeeWithMilk->getCost() . "\n"; // Café simple, con leche - 7

// Añadir azúcar
$coffeeWithMilkAndSugar = new SugarDecorator($coffeeWithMilk);
echo $coffeeWithMilkAndSugar->getDescription() . " - " . $coffeeWithMilkAndSugar->getCost() . "\n"; // Café simple, con leche, con azúcar - 8