Decorator design pattern

Decorator design pattern

What is the problem that this design pattern solves ?

Let's take a classical example of a coffee shop . There is a coffee class . Suppose you want to give user choices to construct object with his choice for eg. Users can add extra whipped cream , mousse toppings or sweet cream . Now we need to define many subclasses to solve the above issue like coffee_with_extra_whipped_cream , coffee_with_mousse_toppings , coffee_with_sweet_cream . Now consider the user wants coffee with extra whipped cream as well as mousse toppings . Now we need to consider each and every combination and create subclasses for it . For this case you may say that it is convenient here . But if there are many possibilities for object creation , it is not a convenient method for defining subclasses for each and every object . This is where the decorator design pattern comes into picture . The main idea in this design pattern is there are concrete classes to construct base objects and there are decorator classes to decorate the object as per users choice . In the above case we will have a coffee class which will act as base class and it will create the base object . There will be the decorator classes like whipped_cream , mousse_toppings , sweet_cream and many more . The reference of the coffee object will be present in decorators and the functions will be present in the decorators to decorate the object as needed .

#include <iostream>
#include <string>

using namespace std;

// Abstract base class for the coffee
class Coffee {
public:
    virtual string getDescription() const = 0;
    virtual double cost() const = 0;
    virtual ~Coffee() {}
};

// Concrete implementation of a basic coffee
class SimpleCoffee : public Coffee {
public:
    string getDescription() const override {
        return "Simple Coffee";
    }

    double cost() const override {
        return 1.0; // Base price for simple coffee
    }
};

// Decorator base class
class CoffeeDecorator : public Coffee {
protected:
    Coffee* coffee;
public:
    CoffeeDecorator(Coffee* c) : coffee(c) {}

    string getDescription() const override {
        return coffee->getDescription();
    }

    double cost() const override {
        return coffee->cost();
    }
};

// Concrete decorator class for adding whipped cream
class WhippedCreamDecorator : public CoffeeDecorator {
public:
    WhippedCreamDecorator(Coffee* c) : CoffeeDecorator(c) {}

    string getDescription() const override {
        return coffee->getDescription() + ", Whipped Cream";
    }

    double cost() const override {
        return coffee->cost() + 0.5; // Extra cost for whipped cream
    }
};

// Concrete decorator class for adding mousse toppings
class MousseToppingsDecorator : public CoffeeDecorator {
public:
    MousseToppingsDecorator(Coffee* c) : CoffeeDecorator(c) {}

    string getDescription() const override {
        return coffee->getDescription() + ", Mousse Toppings";
    }

    double cost() const override {
        return coffee->cost() + 0.75; // Extra cost for mousse toppings
    }
};

// Concrete decorator class for adding sweet cream
class SweetCreamDecorator : public CoffeeDecorator {
public:
    SweetCreamDecorator(Coffee* c) : CoffeeDecorator(c) {}

    string getDescription() const override {
        return coffee->getDescription() + ", Sweet Cream";
    }

    double cost() const override {
        return coffee->cost() + 0.6; // Extra cost for sweet cream
    }
};

int main() {
    // Create a simple coffee
    Coffee* myCoffee = new SimpleCoffee();
    cout << "Description: " << myCoffee->getDescription() << ", Cost: $" << myCoffee->cost() << endl;

    // Add whipped cream
    myCoffee = new WhippedCreamDecorator(myCoffee);
    cout << "Description: " << myCoffee->getDescription() << ", Cost: $" << myCoffee->cost() << endl;

    // Add mousse toppings
    myCoffee = new MousseToppingsDecorator(myCoffee);
    cout << "Description: " << myCoffee->getDescription() << ", Cost: $" << myCoffee->cost() << endl;

    // Add sweet cream
    myCoffee = new SweetCreamDecorator(myCoffee);
    cout << "Description: " << myCoffee->getDescription() << ", Cost: $" << myCoffee->cost() << endl;

    delete myCoffee;

    return 0;
}