8
\$\begingroup\$

I want to make a coffee machine class which can produce coffee with condiments I like, and the price of the final coffee can be easily calculated.

I chose decorator pattern in my design. I've tried making the fields private to follow the principle of making scope as small as possible, but when I implemented the concrete decorator, the getName() caused trouble, I can not use getName() of the beverage in getName() of Milk(ConcreteDecorator). So finally I chose protected.

I've considered this post about using private over protected, but I don't know which one should be better in my implementation. This is a small program but I need some advice about the big picture which I should keep in mind.

So, any advice about any layer of the design of my code is appreciated.

public abstract class Beverage {
    protected final String name;

    public Beverage(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public abstract Double getCost();
}

public class HouseBlend extends Beverage {
    public HouseBlend() {
        super("HouseBlend");
    }

    @Override
    public Double getCost() {
        return 1.5;
    }
}

public abstract class Dairy extends Beverage {
    protected final Beverage beverage;

    public Dairy(String name, Beverage beverage) {
        super(name);
        this.beverage = beverage;
    }

    public Beverage getBeverage() {
        return beverage;
    }

    public abstract String getName();
}

public class Milk extends Dairy {
    public Milk(Beverage beverage) {
        super("Milk", beverage);
    }

    @Override
    public String getName() {
        return name + "-flavored " + beverage.getName();
    }

    @Override
    public Double getCost() {
        return 1.0 + beverage.getCost();
    }
}

public class Butter extends Dairy {
    public Butter(Beverage beverage) {
        super("Butter", beverage);
    }

    @Override
    public String getName() {
        return name + "-above " + beverage.getName();
    }

    @Override
    public Double getCost() {
        return 0.5 + beverage.getCost();
    }
}

public abstract class Sweet extends Beverage {
    protected final Beverage beverage;

    public Sweet(String name, Beverage beverage) {
        super(name);
        this.beverage = beverage;
    }

    public Beverage getBeverage() {
        return beverage;
    }

    public abstract String getName();
}

public class Sugar extends Sweet {

    public Sugar(Beverage beverage) {
        super("Sugar", beverage);
    }

    @Override
    public String getName() {
        return "Strong-" + name + "ed " + beverage.getName();
    }

    @Override
    public Double getCost() {
        return 0.2 + beverage.getCost();
    }
}

UML: Decorator Pattern UML by @N1ng

\$\endgroup\$
  • \$\begingroup\$ It's ObjectAid, a plug-in for Eclipse, and the UML-part is free, for your interest. @JudeNiroshan \$\endgroup\$ – Niing Mar 24 '17 at 5:54
5
\$\begingroup\$

I would remove the name field entirely, and instead inline it into the getName() method. That way you can implement the getName() similar to how you implemented getCost().

Concretely this means your getName() method from Beverage becomes abstract just like the other abstract classes.

public abstract String getName();

The base beverage (HouseBlend) then implements the method as:

public String getName() {
    return "HouseBlend";
}

And similarly the decorator classes implement it as such:

public String getName() {
    return "Milk-flavored " + beverage.getName();
}

You can fill in the implementation for the other decorators.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.