GoF – Patrones de diseño (XI): Decorator

El siguiente patrón de diseño que vamos a ver es el patrón Decorator. Dicho patrón nos permitirá añadir funcionalidades o responsabilidades a un objeto de forma dinámica. Este patrón nos provee de una alternativa muy flexible a la creación de subclases para extender funcionalidades. Esto nos permitirá, en tiempo de ejecución, añadir esta funcionalidad o responsabilidad extra que necesita nuestro objeto. esto se podría hacer a través de la herencia pero no sería lo suficientemente flexible ya que de esta forma serían añadidas de forma estática. En vez de esto, nuestro objeto decorator rodeará al objeto inicial añadiendo estás responsabilidades o funcionalidades. Se hace referencia muchas veces a este patrón como Wrapper. Estoy seguro que este nombre si que lo habréis escuchado muchas veces con anterioridad.

Este patrón lo podemos aplicar para:

  • Añadir responsabilidades a un objeto individual de forma dinámica y transparente sin afectar a otros objetos.
  • Responsabilidades que pueden ser eliminadas de un objeto.
  • Cuando la extensión a través de la herencia no es viable. Por ejemplo, cuando esto provocaría una gran cantidad de subclases o la definición de la clase padre está oculta o no es accesible para realizar esta herencia.

Los elementos implicados en este patrón son:

  • Component: Define la interfaz de los objetos a los que se le podrá añadir responsabilidades dinámicamente.
  • ConcreteComponent: Define el objeto al que se le podrán añadir responsabilidades.
  • Decorator: Mantiene una referencia al objeto Component y define una interfaz que se ajusta a la interfaz de Component.
  • ConcreteDecorator: Añade las responsabilidades al componente.

El uso de este patrón, como ya hemos comentado anteriormente, nos añade mucha más flexibilidad que la herencia estática proveyéndonos de mecanismos para añadir o eliminar responsabilidades en tiempo de ejecución. Quizás el mayor problema que plantea será el de mantenibilidad del código ya que genera muchos objetos pequeños muy similares.

Pero, como siempre, lo mejor de todo es ver esto con un ejemplo. En este caso consistirá en un sistema de envío de emails corporativos.

Component:

public interface IEmail {
    public String getContents();
}

ConcreteComponent:

public class Email implements IEmail {
    private String content;

    public Email(String content) {
        this.content = content;
    }

    @Override
    public String getContents() {
        return content;
    }
}

Decorator;

public abstract class EmailDecorator implements IEmail
    IEmail originalEmail;
}

ConcreteDecorator:

public class ExternalEmailDecorator extends EmailDecorator {
    private String content;

    public ExternalEmailDecorator(IEmail basicEmail) {
        originalEmail = basicEmail;
    }

    @Override
    public String getContents() {
        content = addDisclaimer(originalEmail.getContents());
        return content;
    }

    private String addDisclaimer(String message) {
        return  message + "\n Disclaimer";
    }
}

public class SecureEmailDecorator extends EmailDecorator {
    private String content;

    public SecureEmailDecorator(IEmail basicEmail) {
        originalEmail = basicEmail;
    }

    @Override
    public String getContents() {
        content = encrypt(originalEmail.getContents());
        return content;
    }

    private String encrypt(String message) {
        return encryptedMessage;
    }
}

Main:

public class Sender() {
    public static void main(String[] args) {
        ...
    }

    public String generateEmail(IEmail email, int sentType) {
        String emailText = "";

        switch(sentType) {
            case EXTERNAL:
                EmailDecarator d1 = new ExternalEmailDecorator(email);
                emailText = d1.getContents();
                break;
            case SECURE:
                EmailDecarator d2 = new SecureEmailDecorator(email);
                emailText = d2.getContents();
                break;
            default:
                ...
        }

        return emailText;
    }
}

Como podemos ver en el ejemplo se modifican de forma fácil los emails que queremos enviar.

Otros patrones relacionados con este son: Adapter, aunque similares, se diferencian en que el Decorator modifica solo las responsabilidades del objeto, mientras que el Adapter modifica la interfaz. El Composite, ya que se puede ver al patrón Decorator como una degeneración de este con un solo componente. Strategy, es otra alternativa de cambiar un objeto.

Bueno, hasta aquí hemos llegado por hoy. Nos vemos.

GoF – Patrones de diseño (XI): Decorator

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.