Decorator Pattern

Today we gonna talk about Decorator Pattern.

Every morning, before starting work I drink coffee, sometimes with milk, sometimes with a bar of chocolate.

Let’s imagine the business that seels coffee asked us to write software that will help them selling different types of coffee (Coffe with Milk, Coffe with Chocolate, Coffe with Milk and Chocolate etc).

Our task is to implement a flexible system, the business can ask us to add new ingredients even before delivering software.

For a flexible system that allows decorating beverage with different ingredients, we will use Decorator Pattern:

interface Beverage {
    String getDescription();
    BigDecimal cost();
}

And will implement few base beverages:

class Coffee implements Beverage {

    private final String description = "Coffee";
    private final BigDecimal price = BigDecimal.valueOf(129, CoffeeShop.DEFAULT_SCALE);

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public BigDecimal cost() {
        return price;
    }

    @Override
    public String toString() {
        return "Coffee{" + "description='" + description + '\'' + ", price=" + price + '}';
    }
}
class Tea implements Beverage {

    private final String description = "Tea";
    private final BigDecimal price = BigDecimal.valueOf(99, CoffeeShop.DEFAULT_SCALE);

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public BigDecimal cost() {
        return price;
    }

    @Override
    public String toString() {
        return "Tea{" + "description='" + description + '\'' + ", price=" + price + '}';
    }
}

Now it’s time to prepare ingredients that we can use to decorate our beverages, every time when a new ingredient is added to the beverage, the beverage price changes and the description reflects this.

Observe that ingredients also implements Beverage interface and they are receiving a reference to the beverage that should be decorated:

class MilkDecorator implements Beverage {

    private final String description = "Milk";
    private final BigDecimal price = BigDecimal.valueOf(29, CoffeeShop.DEFAULT_SCALE);

    private final Beverage beverage;

    MilkDecorator(Beverage beverage) {
        this.beverage = beverage;
    }


    @Override
    public String getDescription() {
        return beverage.getDescription() + " with " + description;
    }

    @Override
    public BigDecimal cost() {
        return beverage.cost().add(price);
    }

    @Override
    public String toString() {
        return "MilkDecorator{" + "description='" + description + '\'' + ", price=" + price + ", beverage=" + beverage +
            '}';
    }
}
class ChocolateDecorator implements Beverage {
    private final String description = "Chocolate";
    private final BigDecimal price = BigDecimal.valueOf(35, CoffeeShop.DEFAULT_SCALE);

    private final Beverage beverage;

    ChocolateDecorator(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " with " + description;
    }

    @Override
    public BigDecimal cost() {
        return beverage.cost().add(price);
    }
}

Lets see how we can use this:

class CoffeeShop {
    public static final int DEFAULT_SCALE = 2;

    public static void main(String[] args) {
        //coffee with Milk and Chocolate
        Beverage coffee = new Coffee();
        Beverage coffeeWithMilk = new MilkDecorator(coffee);
        Beverage coffeeWithMilkAndChocolate = new ChocolateDecorator(coffeeWithMilk);
        printBeverage(coffeeWithMilkAndChocolate);

        System.out.println("\n\n");

        //Tea with Chocolate
        Beverage tea = new Tea();
        tea = addChocolate(tea);
        tea = addMilk(tea);
        printBeverage(tea);

    }

    private static Beverage addMilk(Beverage beverage) {
        return new MilkDecorator(beverage);
    }

    private static Beverage addChocolate(Beverage beverage) {
        return new ChocolateDecorator(beverage);
    }

    private static void printBeverage(Beverage beverage) {
        System.out.println("Your Beverage:\n" + beverage.getDescription() +
            "\nPrice: " + beverage.cost().setScale(2, BigDecimal.ROUND_HALF_DOWN));
    }
}

Output:

Your Beverage:
Coffee with Milk with Chocolate
Price: 1.93



Your Beverage:
Tea with Chocolate with Milk
Price: 1.63

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *

Acest site folosește Akismet pentru a reduce spamul. Află cum sunt procesate datele comentariilor tale.