Decorator Pattern Implementation

Structural Patterns in C++

Structural patterns focus on how classes and objects should be composed to achieve specific design goals. One such pattern is the Decorator Pattern, which allows for the dynamic addition of responsibilities to existing classes without altering their structure.

Core Concepts

The decorator pattern is a structural design pattern that enables the extension of existing classes by wrapping them in additional classes (decorators). This approach supports composition over inheritance, ensuring that the original class remains unchanged while new behaviors are added through composition.

The pattern typically involves:

  1. Base Class: The class that defines the interface and methods to be extended.
  2. Decorator Class: A class that wraps the base class and adds new functionality.
  3. Concrete Classes: The actual implementations of the base class and decorators.

Implementation Steps

  1. Define the Base Class: Create a base class with the interface and methods.
  2. Create Decorator Classes: Each decorator implements the same interface as the base class and wraps an instance of the base class.
  3. Chain of Responsibility: Decorators can be chained to add multiple layers of functionality.
  4. Client Code: Use the base class and apply decorators to create composite objects.

Example: Coffee Shop with Toppings

Consider a coffee shop where customers can add toppings to their drinks. The base class is Coffee, and decorators like Milk, Sugar, and WhippedCream add toppings.

class Coffee {
public:
    virtual void prepare() = 0;
    virtual ~Coffee() {}
};
class Milk : public Coffee {
public:
    void prepare() override {
        base->prepare();
        addMilk();
    }
private:
    void addMilk() { /* Add milk */ }
};

class Sugar : public Coffee {
public:
    void prepare() override {
        base->prepare();
        addSugar();
    }
private:
    void addSugar() { /* Add sugar */ }
};

Client Code

A client can create a Coffee object and apply decorators to it:

int main() {
    Coffee* coffee = new Milk();
    coffee->prepare();
    delete coffee;
    return 0;
}

Key Advantages

  • Flexibility: New behaviors can be added dynamically.
  • Separation of Concerns: The original class remains unchanged.
  • Reusability: Decorators can be reused across different objects.

Conclusion

The decorator pattern is a powerful tool in C++ for extending classes without modifying their source code. By leveraging composition, it provides a clean and scalable way to add functionality. This pattern is particularly useful in scenarios where multiple layers of behavior need to be added, such as in a coffee shop or a file system with additional features.