Exemplo do Padrão de Projeto Decorator em Java

O padrão de design Decorator é usado para modificar a funcionalidade de um objeto em tempo de execução. Ao mesmo tempo, outras instâncias da mesma classe não serão afetadas por isso, garantindo que cada objeto individual obtenha o comportamento modificado. O padrão de design Decorator é um dos padrões de design estruturais (como Padrão Adapter, Padrão Bridge, Padrão Composite) e utiliza classes abstratas ou interfaces com composição para implementação.

Padrão de Design Decorator

Nós usamos herança ou composição para estender o comportamento de um objeto, mas isso é feito em tempo de compilação e é aplicável a todas as instâncias da classe. Não podemos adicionar nenhuma nova funcionalidade ou remover qualquer comportamento existente em tempo de execução – é aí que o padrão Decorator entra em cena. Suponha que queiramos implementar diferentes tipos de carros – podemos criar a interface Carro para definir o método de montagem e então podemos ter um Carro Básico, além disso, podemos estendê-lo para Carro Esportivo e Carro de Luxo. A hierarquia de implementação será semelhante à imagem abaixo. Mas se quisermos obter um carro em tempo de execução que tenha tanto as características de um carro esportivo quanto de um carro de luxo, a implementação se torna complexa e, se quisermos especificar quais características devem ser adicionadas primeiro, fica ainda mais complexo. Agora, imagine se tivermos dez tipos diferentes de carros, a lógica de implementação usando herança e composição será impossível de gerenciar. Para resolver esse tipo de situação de programação, aplicamos o padrão decorator em Java. Precisamos ter os seguintes tipos para implementar o padrão de design decorator.

  1. Interface do Componente – A interface ou classe abstrata definindo os métodos que serão implementados. No nosso caso, Carro será a interface do componente.

    pacote com.journaldev.design.decorator;
    
    public interface Carro {
    
    	public void montar();
    }
    
  2. Implementação do Componente – A implementação básica da interface do componente. Podemos ter a classe CarroBasico como nossa implementação do componente.

    pacote com.journaldev.design.decorator;
    
    public class CarroBasico implements Carro {
    
    	@Override
    	public void montar() {
    		System.out.print("Carro Básico.");
    	}
    
    }
    
  3. Decorador – A classe Decorador implementa a interface do componente e tem uma relação HAS-A com a interface do componente. A variável do componente deve ser acessível às classes de decorador filho, então faremos essa variável protegida.

    pacote com.journaldev.design.decorator;
    
    public class CarDecorator implements Car {
    
    	protected Car carro;
    	
    	public CarDecorator(Car c){
    		this.carro=c;
    	}
    	
    	@Override
    	public void montar() {
    		this.carro.montar();
    	}
    
    }
    
  4. Decoradores Concretos – Estendendo a funcionalidade básica do decorador e modificando o comportamento do componente de acordo. Podemos ter classes de decorador concretas como CarroLuxuoso e CarroEsportivo.

    pacote com.journaldev.design.decorator;
    
    public class SportsCar extends CarDecorator {
    
    	public SportsCar(Car c) {
    		super(c);
    	}
    
    	@Override
    	public void montar(){
    		super.montar();
    		System.out.print(" Adicionando recursos de Carro Esportivo.");
    	}
    }
    
    pacote com.journaldev.design.decorator;
    
    public class LuxuryCar extends CarDecorator {
    
    	public LuxuryCar(Car c) {
    		super(c);
    	}
    	
    	@Override
    	public void montar(){
    		super.montar();
    		System.out.print(" Adicionando recursos de Carro de Luxo.");
    	}
    }
    

Padrão de Projeto Decorator – Diagrama de Classe

Programa de Teste do Padrão de Projeto Decorator

package com.journaldev.design.test;

import com.journaldev.design.decorator.BasicCar;
import com.journaldev.design.decorator.Car;
import com.journaldev.design.decorator.LuxuryCar;
import com.journaldev.design.decorator.SportsCar;

public class DecoratorPatternTest {

	public static void main(String[] args) {
		Car sportsCar = new SportsCar(new BasicCar());
		sportsCar.assemble();
		System.out.println("\n*****");
		
		Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
		sportsLuxuryCar.assemble();
	}

}

Observe que o programa cliente pode criar diferentes tipos de objetos em tempo de execução e também pode especificar a ordem de execução. A saída do programa de teste acima é:

Basic Car. Adding features of Sports Car.
*****
Basic Car. Adding features of Luxury Car. Adding features of Sports Car.

Padrão de Projeto Decorator – Pontos Importantes

  • O padrão de projeto decorator é útil para fornecer capacidades de modificação em tempo de execução e, portanto, é mais flexível. É fácil de manter e estender quando o número de opções é maior.
  • A desvantagem do padrão de projeto decorator é que ele usa muitos objetos do mesmo tipo (decoradores).
  • **Tradução para o Português:**

    O padrão Decorator é muito utilizado em classes de Java IO, como FileReader, BufferedReader, etc.

Source:
https://www.digitalocean.com/community/tutorials/decorator-design-pattern-in-java-example