Exemplo do Padrão de Design Decorator em Java

O padr dePad designr Decorãoator de é design usado Decorator para é func usadoional para modificaridade a de func umional objetoidade em de tempo um de objeto exec emução tempo. Ao de mesmo exec tempoução,. Ao outras mesmo instâ temponcias, da mesma outras classe inst nãoâ serãoncias af daet mesmaadas classe por não isso serão, af entãoet o objetoadas individual por isso obt,ém garant oindo comport queamento cada mod objetoificado individual. obten Oha padr oão comportamento modificado. O padrão de de design Decor designator é um dos padr Decorões de designator estr é umut dos padruralões (como o de Padr designão de Adapt estrador, out Padrãoural de Pont (e, ocomo Padrão < Compostdio) ey usa classes3>Pad abrstrãoatas de ou Adapt interfacesador com,. Padrão de Ponte, Padrão Composto) e utiliza classes abstratas ou interfaces com composição para implementação.

Padrão de Design Decorator

Nós usamos a 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 Car para definir o método de montagem e, em seguida, podemos ter um carro básico, e ainda mais, podemos estendê-lo para Carro Esportivo e Carro de Luxo. A hierarquia de implementação será parecida com a 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 fica 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 decorador em Java. Precisamos ter os seguintes tipos para implementar o padrão de design do decorador.

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

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

    package 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 de 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 car;
    	
    	public CarDecorator(Car c){
    		this.car=c;
    	}
    	
    	@Override
    	public void montar() {
    		this.car.montar();
    	}
    
    }
    
  4. Decoradores Concretos – Estendendo a funcionalidade do decorador base e modificando o comportamento do componente conforme necessário. Podemos ter classes de decoradores concretos como CarroLuxo e CarroEsportivo.

    pacote com.journaldev.design.decorator;
    
    public class CarroEsportivo extends CarDecorator {
    
    	public CarroEsportivo(Car c) {
    		super(c);
    	}
    
    	@Override
    	public void montar(){
    		super.montar();
    		System.out.print(" Adicionando características do Carro Esportivo.");
    	}
    }
    
    pacote com.journaldev.design.decorator;
    
    public class CarroLuxo extends CarDecorator {
    
    	public CarroLuxo(Car c) {
    		super(c);
    	}
    	
    	@Override
    	public void montar(){
    		super.montar();
    		System.out.print(" Adicionando características do 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 habilidades de modificação em tempo de execução e, portanto, mais flexibilidade. É fácil de manter e estender quando o número de escolhas é maior.
  • A desvantagem do padrão de projeto decorator é que ele usa muitos objetos semelhantes (decoradores).
  • O padrão de decorador é muito usado em classes de Java IO, como FileReader, BufferedReader etc.

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