Padrão Chain of Responsibility

Objetivo desse padrão é encadear objetos receptores sem que haja uma dependência entre eles.

Olha para imagem abaixo, o handler é uma interface para suas implementações concretas que possuí o método requestHandler, que define qual vai ser o sucessor da implementação atual, por isso o nome Chain of Responsibility, pois o objeto atual tem o conhecimento do próximo passo, assim formando uma cadeia de responsabilidades.

Design Pattern - Chain of Responsibility
Design Pattern – Chain of Responsibility

Por exemplo, no código abaixo poderia ser aplicado o padrão Chain of Responsibility:

 
public class CalculadorDeDesconto {

   public static void main(String[] args) {
       final Pedido pedido = new Pedido;
       calculaDesconto(pedido);
   }   

   public BigDecimal calculaDesconto(Pedido pedido) {
        if(pedido.getItens().size() > 10) {
            return pedido.getValor().multiply(BigDecimal.valueOf(0.5));
        } else if(pedido.getValor() > 1000.0) {
            return pedido.getValor().multiply(BigDecimal.valueOf(0.10));
        } else {
            return BigDecimal.ZERO;
        }
   }
}

O problema dessa abordagem é a quantidade de condições(“ifs”) concatenadas que podem ter nesse método de calculaDesconto, o que deixa o código mais complexo para manutenção.

Aplicando o padrão Chain of Responsibility o código ficaria da seguinte forma:

 

public interface Desconto {
    BigDecimal calcular(Pedido pedido);
}

public class DescontoPorItens implements Desconto {
       
    private Desconto proximo;

    public void setProximo(Desconto proximo) {
       this.proximo = proximo;
    }

    public BigDecimal calcular(Pedido pedido) {
        if(pedido.getValor() > 1000.0) {
            return pedido.getValor().multiply(BigDecimal.valueOf(0.10));
        }else {
            return proximo.calcular(pedido);
       }
    }
}

public class DescontoPorValor implements Desconto {
       
     private Desconto proximo;

     public void setProximo(Desconto proximo) {
         this.proximo = proximo;
     }

     public BigDecimal calcular(Pedido pedido) {
        if(pedido.getItens().size() > 10) {
            return pedido.getValor().multiply(BigDecimal.valueOf(0.5));
        }else {
            return proximo.calcular(pedido);
       }
     }
}

public class SemDesconto implements Desconto {

    public BigDecimal calcular(Pedido pedido) {
       return BigDecimal.ZERO;
    }

    public void setProximo(Desconto desconto) {
       // Não faz nada, é o último nível
    }
}

public class CalculadorDeDesconto {

   public static void main(String[] args) {
       final Pedido pedido = new Pedido;
       calculaDesconto(pedido);
   }   

   public BigDecimal calculaDesconto(Pedido pedido) {
        final Desconto descontoPorItem = new DescontoPorItens();
        final Desconto descontoPorValor = new DescontoPorValor();
        final Desconto semDesconto = new SemDesconto();

        descontoPorItem.setProximo(descontoPorValor);
        descontoPorValor.setProximo(semDesconto);

        return descontoPorItem.calcular(pedido);
   }
}

Com isso, após a aplicação do padrão Chain of Responsibility fica com menor acoplamento entre as condições, onde há apenas a definição do “próximo”, que é uma implementação da interface Desconto, e com menor complexidade, pois cada classe concreta é responsável por sua lógica de calcular o desconto.

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s