# Patrón de diseño Decorator en PHP


## Patrón de diseño DECORATOR en PHP

En este post quiero enseñarte otro patrón de diseño que utilizo comúnmente en los proyectos que he tenido la oportunidad de trabajar y es el** patrón de diseño DECORATOR **o Decorador.

Este patrón nos permite resolver el problema de agregar comportamiento o funcionalidad específica a los objetos de una clase. La POO nos permite recurrir a la herencia cuando se trata de añadir funcionalidad extra a nuestra clase.

Pero, el problema radica en que no podemos heredar de más de una clase, es decir, dada una clase C, no podrá heredar a la vez de una clase A y B.

Es por eso que el patrón de diseño **Decorator** nos permite añadir comportamiento específico a los objetos de una clase sin tener que añadirlo a la clase como tal.

Por otro lado, nos permite conservar el principio de **Open/Closed **del patrón de diseño **SOLID** visto en** este post**. En donde cada entidad o clase esta abierta para su extensión pero cerrada para su modificación.
> *También nos permite mantener nuestras clases con responsabilidades únicas por ende nuestras clases evitan complejidad y se mantienen ligeras de código.*
> *Se acopla también al principio **Single Responsability** de **SOLID***

## Ejemplo de implementación del patrón de diseño DECORATOR en PHP

Para este ejemplo imaginemos que necesitamos calcular el precio de una Macbook basado en su versión y tamaño de pantalla.

Lo primero seria definir nuestra clase **Macbook** la cual implementa el getter para obtener el precio base del producto.

```
class Macbook
{
    protected $basePrice = 1500;
    
    public function getPrice()
    {
        return $this->basePrice;
    }
}
```


Lo siguiente es generar nuestra clase abstracta decoradora la cual llamaremos **MacbookDecorator**

```
abstract class MacbookDecorator
{
    protected $price;
    protected $macbook;
    public function __construct($macbook)
    {
        $this->macbook = $macbook;
    }
    public function getPrice()
    {
        return $this->macbook->getPrice() + $this->price;
    }
}
```


Como podemos ver, añade una nueva funcionalidad la cual es calcular el precio base de la macbook en donde sumamos el precio base con el precio según la versión y tamaño de la pantalla. Verémos mas adelante como funciona.

Ahora vamos a crear una versión nueva del macbook el cual incrementará el precio de la macbook base. Añadiremos la versión MacbookPro, para ello creamos nuestra clase **MacbookPro** la cual va a extender de nuestro decorador.

```
class MacbookPro extends MacbookDecorator 
{ 
  protected $price = 950; 
}
```


De igual forma crearemos dos clases para nuestros tamaños de pantalla disponible.

```
class WithDisplaySize15 extends MacbookDecorator 
{ 
  protected $price = 350; 
}

class WithDisplaySize17 extends MacbookDecorator 
{ 
  protected $price = 700; 
}
```


Gracias al decorator podemos combinar nuestras clases para generar variantes de nuestro producto por ejemplo para nuestra tienda de e-commerce.

## Probando la implementación anterior

Para probar veamos lo siguiente:

```
$macbook = new Macbook();
echo 'Una Macbook con pantalla de 13 pulgadas cuesta ' . $macbook->getPrice() . ' euros' . PHP_EOL;

$macbook15Pulg = new WithDisplaySize15(new Macbook());
echo 'Una Macbook con pantalla de 15 pulgadas cuesta ' . $macbook15Pulg->getPrice() . ' euros' . PHP_EOL;

$macbook17Pulg = new WithDisplaySize17(new Macbook());
echo 'Una Macbook con pantalla de 17 pulgadas cuesta ' . $macbook17Pulg->getPrice() . ' euros' . PHP_EOL;

$macbookPro = new MacbookPro(new Macbook());
echo 'Una Macbook Pro con pantalla de 13 pulgadas cuesta ' . $macbookPro->getPrice() . ' euros' . PHP_EOL;

$macbookPro15Pulg = new WithDisplaySize15(new MacbookPro(new Macbook()));
echo 'Una Macbook Pro con pantalla de 15 pulgadas cuesta' . $macbookPro15Pulg->getPrice() . ' euros' . PHP_EOL;

$macbookPro17Pulg = new WithDisplaySize17(new MacbookPro(new Macbook()));
echo 'Una Macbook Pro con patanlla de 17 pulgadas cuesta ' . $macbookPro17Pulg->getPrice() . ' euros' . PHP_EOL;
```


Con esta implementación, podremos tener el precio de la macbook base ( que viene con 13 pulgadas), la misma versión pero con pantalla de 15 y 17 pulgadas respectivamente.

Lo mismo con la versión MacbookPro. Puedes ver el de este ejemplo en mi [**github](https://gist.github.com/fjugaldev/fda87196efa5d5675bf885ebb03b3ede)**

Otra forma de implementar en este patrón de diseño es por ejemplo en nuestros ApplicationServices o UseCases en donde cada uno tiene una funcionalidad específica pero queremos que cuando se ejecuten, se registre un log y se notifique por email sobre la acción realizada.

Aquí el approach seria, crear un decorator para nuestros ApplicationServices en donde inyectemos nuestra clase Logger y nuestra clase Mailer y de cierta forma añadimos funcionalidad extra de una forma simple y sutil, sin sobrecargar nuestras clases y sin repetir funcionalidad.

Hasta aqui todo lo relacionado con este patrón de diseño super útil y que debemos tener en cuenta para nuestros desarrollos.

Todo el contenido del ejemplo puedes conseguirlo en este [**gist](https://gist.github.com/fjugaldev/fda87196efa5d5675bf885ebb03b3ede)** de Github.

Recuerda que si tienes alguna sugerencia o pregunta, no dudes en dejar tus comentarios al final del post.

Si te gustó este post, ayúdame a que pueda servirle a muchas más personas, compartiendo mis contenidos en tus redes sociales.

Espero que este post haya sido de gran ayuda para ti, y como siempre, cualquier inquietud o duda que tengas, puedes contactarme por cualquiera de las vías disponibles, o dejando tus comentarios al final de este post. También puedes sugerir que temas o post te gustaría leer a futuro.
