O Padrão Decorador em Java

O Padrão Decorador em Java

1. Visão geral

A Decorator pattern can be used to attach additional responsibilities to an object either statically or dynamically. Um Decorator fornece uma interface aprimorada para o objeto original.

Na implementação desse padrão, preferimos a composição do que uma herança - para que possamos reduzir a sobrecarga da subclasse várias vezes para cada elemento de decoração. A recursão envolvida com esse design pode ser usada para decorar nosso objeto quantas vezes for necessário.

2. Exemplo de padrão de decorador

Suponha que temos um objeto de árvore de Natal e queremos decorá-lo. A decoração não altera o próprio objeto; é que, além da árvore de Natal, estamos adicionando alguns itens de decoração, como guirlanda, enfeites, enfeites de árvore, luzes de bolha, etc .:

image

For this scenario, we’ll follow the original Gang of Four design and naming conventions. Primeiro, criaremos uma interfaceChristmasTree e sua implementação:

public interface ChristmasTree {
    String decorate();
}

A implementação desta interface será semelhante a:

public class ChristmasTreeImpl implements ChristmasTree {

    @Override
    public String decorate() {
        return "Christmas tree";
    }
}

Vamos agora criar uma classe abstrataTreeDecorator para esta árvore. Este decorador implementará a interfaceChristmasTree e também manterá o mesmo objeto. O método implementado da mesma interface simplesmente chamará o métododecorate() de nossa interface:

public abstract class TreeDecorator implements ChristmasTree {
    private ChristmasTree tree;

    // standard constructors
    @Override
    public String decorate() {
        return tree.decorate();
    }
}

Agora vamos criar algum elemento de decoração. Esses decoradores estenderão nossa classe abstrataTreeDecorator e modificarão seu métododecorate() de acordo com nosso requisito:

public class BubbleLights extends TreeDecorator {

    public BubbleLights(ChristmasTree tree) {
        super(tree);
    }

    public String decorate() {
        return super.decorate() + decorateWithBubbleLights();
    }

    private String decorateWithBubbleLights() {
        return " with Bubble Lights";
    }
}

Para este caso, o seguinte é verdadeiro:

@Test
public void whenDecoratorsInjectedAtRuntime_thenConfigSuccess() {
    ChristmasTree tree1 = new Garland(new ChristmasTreeImpl());
    assertEquals(tree1.decorate(),
      "Christmas tree with Garland");

    ChristmasTree tree2 = new BubbleLights(
      new Garland(new Garland(new ChristmasTreeImpl())));
    assertEquals(tree2.decorate(),
      "Christmas tree with Garland with Garland with Bubble Lights");
}

Observe que, no primeiro objetotree1, estamos decorando-o apenas com umGarland, enquanto o outro objetotree2 estamos decorando com umBubbleLightse doisGarlands. Esse padrão nos dá essa flexibilidade para adicionar quantos decoradores quisermos em tempo de execução.

4. Conclusão

Neste artigo, vimos o padrão de design do decorador. Essa é uma boa escolha nos seguintes casos:

  • Quando queremos adicionar, aprimorar ou até remover o comportamento ou o estado dos objetos

  • Quando queremos apenas modificar a funcionalidade de um único objeto de classe e deixar outros inalterados

O código-fonte completo para este exemplo está disponívelover on GitHub.