Files
java-design-patterns/localization/es/decorator

title, shortTitle, category, language, tag
title shortTitle category language tag
Decorator Decorator Structural es
Gang of Four
Extensibility

También conocido como

Wrapper

Propósito

Adjunte responsabilidades adicionales a un objeto de forma dinámica. Los decoradores proporcionan una alternativa flexible a la subclase para ampliar la funcionalidad.

Explicación

Ejemplo real

En las colinas cercanas vive un trol furioso. Normalmente va con las manos desnudas, pero a veces lleva un arma. Para armar al troll no es necesario crear un nuevo troll sino decorarlo dinámicamente con un arma adecuada.

En pocas palabras

El patrón decorador permite cambiar dinámicamente el comportamiento de un objeto en tiempo de ejecución envolviéndolo en un objeto de una clase decoradora.

Wikipedia says

En programación orientada a objetos, el patrón decorador es un patrón de diseño que permite añadir comportamiento a un objeto individual, ya sea de forma estática o dinámica, sin afectar al comportamiento de otros objetos de la misma clase. El patrón decorador suele ser útil para adherirse al Principio de Responsabilidad Única, ya que permite dividir la funcionalidad entre clases con áreas de interés únicas, así como al Principio Abierto-Cerrado, al permitir extender la funcionalidad de una clase sin modificarla.

Ejemplo programático

Tomemos el ejemplo del troll. En primer lugar tenemos un SimpleTroll que implementa la interfaz Troll:

public interface Troll {
  void atacar();
  int getPoderAtaque();
  void huirBatalla();
}

@Slf4j
public class SimpleTroll implements Troll {

  @Override
  public void atacar() {
    LOGGER.info("¡El troll intenta atraparte!");
  }

  @Override
  public int getPoderAtaque() {
    return 10;
  }

  @Override
  public void huirBatalla() {
    LOGGER.info("¡El troll chilla de horror y huye!");
  }
}

A continuación, queremos añadir un palo para el troll. Podemos hacerlo de forma dinámica mediante el uso de un decorador:

@Slf4j
public class TrollConGarrote implements Troll {

  private final Troll decorado;

  public TrollConGarrote(Troll decorado) {
    this.decorado = decorado;
  }

  @Override
  public void atacar() {
    decorado.atacar();
    LOGGER.info("¡El troll te golpea con un garrote!");
  }

  @Override
  public int getPoderAtaque() {
    return decorado.getPoderAtaque() + 10;
  }

  @Override
  public void huirBatalla() {
    decorado.huirBatalla();
  }
}

Aquí está el troll en acción:

// troll simple
LOGGER.info("Un troll de aspecto simple se acerca.");
var troll = new SimpleTroll();
troll.atacar();
troll.huirBatalla();
LOGGER.info("Poder del troll simple: {}.\n", troll.getPoderAtaque());

// cambia el comportamiento del troll simple agregando un decorador
LOGGER.info("Un troll con un enorme garrote te sorprende.");
var trollConGarrote = new TrollConGarrote(troll);
trollConGarrote.atacar();
trollConGarrote.huirBatalla();
LOGGER.info("Poder del troll con garrote: {}.\n", trollConGarrote.getPoderAtaque());

Salida del programa:

Un troll de aspecto simple se acerca. 
¡El troll intenta atraparte!
¡El troll chilla de horror y huye!
Poder del troll simple: 10.

Un troll con un enorme garrote te sorprende.
¡El troll intenta atraparte!
¡El troll te golpea con un garrote!
¡El troll chilla de horror y huye!
Poder del troll con garrote: 20.

Diagrama de clases

alt text

Aplicabilidad

Decorator se utiliza para:

  • Añadir responsabilidades a objetos individuales de forma dinámica y transparente, es decir, sin afectar a otros objetos.
  • Para responsabilidades que pueden ser retiradas.
  • Cuando la extensión por subclase es poco práctica. A veces es posible un gran número de extensiones independientes son posibles y producirían una explosión de subclases para soportar cada combinación. O la definición de una clase puede estar oculta o no estar disponible para subclases.

Tutoriales

Usos conocidos

Créditos