Gente, comecei a estudar design patterns com o livro head first - design patterns. No capítulo 3, onde é abordado o padrão Decorator, o autor implementa um sistema para uma lanchonete que vende cafés.
Só para explicar para quem não tem o livro, a lanchonete cobra pelo café de acordo com o tipo de café e com os condimentos adicionados a ele.
Assim, o cliente pede um café Expresso, que custa 1 real e adiciona leite (.50 centavos), chocolate (.20) e “whip” (.30).
Então como resultado ele mostra o preço: 2 reais e a lista de condimentos adicionados: "café expresso + chocolate, leite e “whip”.
Para implementar o negocio ele usou o padrão Decorator, fazendo algo como é mostrado no diagrama de classe da imagem em anexo.
As classes dos tipos de café ele implementou ± assim:
public Espresso ()
{
description = "Expresso";
}
public double cost()
{
return 1.99;
}
Os métodos cost() e getDescription() das classes CondimentDecorator são implementadas assim:
public Mocha(Beverage beverage)
{
this.beverage = beverage;
}
public double cost ()
{
return .20 + beverage.cost();
}
public String getDescription()
{
return beverage.getDescription() + ", milk";
}
nas classes abstratas não há muita implementação.
e na classe em que o programa é executado é feito isso:
Beverage beverage = new Espresso();
beverage = new Mocha(beverage);
beverage = new Whip (beverage);
Ai a cada vez que ele cria uma instância de um condimento o preço é adicionado ao condimento.
eu tentei implementar de outro jeito:
public interface Beverage {
public String getDescription();
public double getCost();
public void setDescription(String description);
public void setCost(double cost);
}
public class PureBeverage implements Beverage{
private String description = "unknow";
private double cost = .0;
private ArrayList <CondimentDecorator> condiments = new ArrayList <CondimentDecorator> ();
public void setCost(double cost) {
this.cost = cost;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription()
{
return description;
}
public double getCost ()
{
return cost;
}
public void addCondiment (CondimentDecorator decorator)
{
this.cost += decorator.getCost();
this.description += decorator.getDescription();
condiments.add(decorator);
}
}
public class Espresso extends PureBeverage{
public Espresso()
{
setCost(.75);
setDescription("Café expresso ");
}
}
public class CondimentDecorator implements Beverage{
private double cost;
private String description;
public double getCost() {
return cost;
}
public String getDescription() {
return description;
}
public void setCost(double cost) {
this.cost = cost;
}
public void setDescription(String description) {
this.description = description;
}
}
public class Milk extends CondimentDecorator{
public Milk ()
{
setCost(.20);
setDescription(", milk");
}
}
public class StarbuzzCafe {
public static void main(String[] args) {
PureBeverage beverage = new Decaf();
beverage.addCondiment(new Mocha());
beverage.addCondiment(new Milk());
beverage.addCondiment(new Whip());
System.out.println("Descrição: "+beverage.getDescription());
System.out.println("Preço: "+beverage.getCost());
}
}
Achei que desta forma seria mais intuitivo, porque ai fica explícito que estou adicionando condimentos. Olhando por cima, pela minha pouca experiência que tenho com essas coisas, acho que não haveria muitos problemas de manutenção depois, se for preciso adicionar novos tipos de bebidas ou novos condimentos.
Perguntas:
Vocês conseguem indentificar algum problema no jeito como eu implementei?
Do jeito que eu fiz o negocio, continua sendo padrão decorator ou deixou de ser?
Tem alguma forma de melhorar isso tudo?