Objetivo desse padrão é encadear objetos receptores sem que haja uma dependência entre eles.
Olhando 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.

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); void setProximo(Desconto proximo); } public class DescontoPorItens implements Desconto { private Desconto proximo; @Override public BigDecimal calcular(Pedido pedido) { if(pedido.getItens().size() > 10) { return pedido.getValor().multiply(BigDecimal.valueOf(0.5)); } else { return proximo.calcular(pedido); } } @Override public void setProximo(Desconto proximo) { this.proximo = proximo; } } public class DescontoPorValor implements Desconto { private Desconto proximo; @Override public BigDecimal calcular(Pedido pedido) { if(pedido.getValor() > 1000.0) { return pedido.getValor().multiply(BigDecimal.valueOf(0.10)); } else { return proximo.calcular(pedido); } } @Override public void setProximo(Desconto proximo) { this.proximo = proximo; } } public class SemDesconto implements Desconto { @Override public BigDecimal calcular(Pedido pedido) { return BigDecimal.ZERO; } @Override 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.
Estava olhando as implementações de DescontoPorItens e DescontoPorValor, e aparentemente as implementações estão trocadas, pois DescontoPorItens testa o valor do pedido “pedido.getValor() > 1000.0”, já DescontoPorValor testa a quantidade de itens, “pedido.getItens().size() > 10”. Ou eu entendi errado?
CurtirCurtir
Isso mesmo Alex você entendeu corretamente, as validações estão trocadas, fiz a correção no código do post. Muito obrigado por comentar, abraço.
CurtirCurtir
Faltou declarar o método setProximo() na interface Desconto, não?
CurtirCurtir
Faltou mesmo, vou fazer a correção, obrigado Israel!
CurtirCurtir