You are on page 1of 5

Nosso orçamento pode receber um desconto de acordo com o tipo da venda que será efet

uada. Por exemplo, se o cliente comprou mais de 5 ítens, ele recebe 10% de descont
o; se ele fez uma compra casada de alguns produtos, recebe 5% de desconto, e ass
im por diante.
Em uma implementação tipicamente procedural, teríamos algo do tipo:
public class CalculadorDeDescontos {
public double calcula(Orcamento orcamento) {
// verifica primeira regra de possível desconto
if(orcamento.getItens().size > 5) {
return orcamento.getValor() * 0.1;
}
// verifica segunda regra de possível desconto
else if(orcamento.getValor() > 500.0) {
return orcamento.getValor() * 0.07;
}
// verifica terceira, quarta, quinta regra de possível desconto ...
// um monte de ifs daqui pra baixo
}
}
Ver esse monte de ifs em sequência nos lembra o capítulo anterior, na qual extraímos c
ada um deles para uma classe específica. Vamos repetir o feito, já que com classes m
enores, o código se torna mais simples de entender:
public class DescontoPorCincoItens {
public double desconta(Orcamento orcamento) {
if(orcamento.getItens().size > 5) {
return orcamento.getValor() * 0.1;
}
else {
return 0;
}
}
}
public class DescontoPorMaisDeQuinhentosReais {
public double desconta(Orcamento orcamento) {
if(orcamento.getValor() > 500) {
return orcamento.getValor() * 0.07;
}
else {
return 0;
}
}
}
Veja que tivemos que sempre colocar um return 0;, afinal o método precisa sempre r
etornar um double. Vamos agora substituir o conjunto de ifs na classe Calculador
DeDesconto. Repare que essa classe procura pelo desconto que deve ser aplicado;
caso o anterior não seja válido, tenta o próximo.
public class CalculadorDeDescontos {
public double calcula(Orcamento orcamento) {
// vai chamando os descontos na ordem até que algum deles dê diferente de ze
ro...
double desconto = new DescontoPorCincoItens().desconta(orcamento);
if(desconto == 0)
desconto = new DescontoPorMaisDeQuinhentosReais().desconta(orcamento);
if(desconto == 0)

} public class DescontoPorMaisDeQuinhentosReais implements Desconto { . public void setProximo(Desconto proximo) { this.07. } public class DescontoPorCincoItens implements Desconto { .. } Para fazer aquele código funcionar agora.desconta(orcamento). basta fazer com que todo desconto receba um próximo desconto! Observe o código abaixo: public interface Desconto { double desconta(Orcamento orcamento). O p roblema agora é como fazer essa sequência de descontos ser aplicada na ordem. } } O código já está um pouco melhor.getValor() * 0.1.getValor() > 500) { return orcamento. // .size > 5) { return orcamento. } } } public class DescontoPorMaisDeQuinhentosReais implements Desconto { private Desconto proximo.... public void setProximo(Desconto proximo) { . Precisávamos fazer com que um desconto qualquer.getValor() * 0. Cada regra de negócio está em sua respectiva classe. Todos eles calculam o desconto dado um orçamen to.desconto = new ProximoDesconto(). } else { return proximo. return desconto.getItens(). void setProximo(Desconto proximo) } public class DescontoPorCincoItens implements Desconto { private Desconto proximo. } else { return PROXIMO DESCONTO.desconta(orcamento). } } } Todos os descontos têm algo em comum. Algo do tipo: public class DescontoPorMaisDeQuinhentosReais { public double desconta(Orcamento orcamento) { if(orcamento.. automa ticamente passe para o próximo. até encontrar um que faça sentido.. Por exemplo: public interface Desconto { double desconta(Orcamento orcamento). caso não deva ser executado. } public double desconta(Orcamento orcamento) { if(orcamento. pois p recisamos colocar mais um if sempre que um novo desconto aparecer. Podemos criar uma abstração para representar um desconto genérico.proximo = proximo.

o mesmo já calcula o desconto . } } public class TestaDescontos { public static void main(String[] args) { CalculadorDeDescontos calculador = new CalculadorDeDescontos().getValor() > 500) { return orcamento. devemos realizar alguma ação.setProximo(d2).calcula(orcamento). 250. ou seja. Orcamento orcamento = new Orcamento(500. Vamos criar a classe SemDesconto. qualquer que seja esse próximo desconto. . Caso contrário. o valor deve ser 0. A ideia do padrão é resolver problemas como esses: de acordo com o cenário.getValor() * 0. Daí o nome do padrão de projeto: Chain of Responsibility. Para o desconto.this. Veja que um desconto recebe um "próximo". e deixarmos um único método descobrir o que deve ser feito.0)).07. } } } Ou seja.out. Nosso problema é só fazer o algoritmo parar agora.0)). um ligado ao outro . orcamento. System.desconta(orcamento). que será o fim da co rrente. Eles estão totalme nte desacoplados um do outro! public class CalculadorDeDescontos { public double calcula(Orcamento orcamento) { Desconto d1 = new DescontoPorCincoItens(). ele passa para o "próximo" desconto.0). pouco importa qual é o próximo desconto. return d1. d1.println(desconto). } public double desconta(Orcamento orcamento) { if(orcamento. } } Esses descontos formam como se fosse uma "corrente". orcamento. e as unimos como uma corrente. Se ele não encontrar nenhum descont o válido.adicionaItem(new Item("LAPIS". se o orçamento atende a regra de um desconto. Basta agora plugarmos todas essas classes juntas.desconta(orcamento).adicionaItem(new Item("CANETA". 250. public class SemDesconto implements Desconto { public double calcula(Orcamento orcamento) { return 0. } else { return proximo. double desconto = calculador. Ao invés d e escrevermos código procedural.proximo = proximo. quebramos essas responsabilidades em várias diferentes classes. Desconto d2 = new DescontoPorMaisDeQuinhentosReais().

itens = new ArrayList<Item>(). } } A classe SemDesconto não atribui o próximo desconto. this. } } public class Item { private String nome. ela é o ponto final da nossa cadeia de responsabilidades. } public String getNome() { return nome.unmodifiableList(itens). private List<Item> itens.setProximo(d3). return d1.add(item). Na realidade.} public void setProximo(Desconto desconto) { // nao tem! } } public class CalculadorDeDescontos { public double calcula(Orcamento orcamento) { Desconto d1 = new DescontoPorCincoItens(). private double valor. d1.valor = valor.desconta(orcamento). e agora recebe ítens também.setProximo(d2). pois ela não possui um próximo. A mudança é s imples: public class Orcamento { private double valor. } public void adicionaItem(Item item) { itens. .nome = nome. d2. Note também que nossa classe Orcamento cresceu.valor = valor. double valor) { this. } public double getValor() { return valor. Desconto d2 = new DescontoPorMaisDeQuinhentosReais(). Desconto d3 = new SemDesconto(). this. public Orcamento(double valor) { this. } public List<Item> getItens() { return Collections. public Item(String nome.

} } .} public double getValor() { return valor.