Decorator Pattern
Tags: designpatterns, softwaredesign, oop
Published: 2024-06-17 10:25:21

### Step-by-Step Guide to Implementing the Decorator Pattern

The Decorator Pattern is a structural design pattern that allows you to dynamically add behavior to an object without affecting the behavior of other objects from the same class. It provides a flexible alternative to subclassing for extending functionality.

#### 1. Understand the Concept

The Decorator Pattern involves the following key components:
- **Component Interface**: An abstract class or interface that defines the operations.
- **Concrete Component**: A class that implements the Component interface.
- **Decorator**: An abstract class that implements the Component interface and has a reference to a Component object.
- **Concrete Decorators**: Classes that extend the Decorator class and add functionalities to the Component.

#### 2. Define the Example Scenario

Let's consider a real-world example: A coffee shop where you can order different types of coffee and add various condiments (like milk, sugar, and whipped cream) dynamically.

#### 3. Implementing the Example

**Step 1: Define the Component Interface**

First, create an interface or abstract class for the coffee:





**Step 2: Create Concrete Components**

Next, create concrete implementations of the Coffee class:

```csharp
public class Espresso : Coffee
{
    public override string GetDescription()
    {
        return "Espresso";
    }

    public override double Cost()
    {
        return 1.99;
    }
}

public class HouseBlend : Coffee
{
    public override string GetDescription()
    {
        return "House Blend Coffee";
    }

    public override double Cost()
    {
        return 0.89;
    }
}
```

**Step 3: Create the Decorator Abstract Class**

Create an abstract decorator class that implements the Coffee interface and holds a reference to a Coffee object:

```csharp
public abstract class CoffeeDecorator : Coffee
{
    protected Coffee _coffee;

    public CoffeeDecorator(Coffee coffee)
    {
        _coffee = coffee;
    }

    public override string GetDescription()
    {
        return _coffee.GetDescription();
    }

    public override double Cost()
    {
        return _coffee.Cost();
    }
}
```

**Step 4: Create Concrete Decorators**

Now, create concrete decorators that extend the CoffeeDecorator class and add functionalities:

```csharp
public class Milk : CoffeeDecorator
{
    public Milk(Coffee coffee) : base(coffee)
    {
    }

    public override string GetDescription()
    {
        return _coffee.GetDescription() + ", Milk";
    }

    public override double Cost()
    {
        return _coffee.Cost() + 0.50;
    }
}

public class Sugar : CoffeeDecorator
{
    public Sugar(Coffee coffee) : base(coffee)
    {
    }

    public override string GetDescription()
    {
        return _coffee.GetDescription() + ", Sugar";
    }

    public override double Cost()
    {
        return _coffee.Cost() + 0.20;
    }
}

public class WhippedCream : CoffeeDecorator
{
    public WhippedCream(Coffee coffee) : base(coffee)
    {
    }

    public override string GetDescription()
    {
        return _coffee.GetDescription() + ", Whipped Cream";
    }

    public override double Cost()
    {
        return _coffee.Cost() + 0.70;
    }
}
```

**Step 5: Use the Decorators**

Finally, use the decorators to dynamically add functionalities to the coffee objects:

```csharp
class Program
{
    static void Main(string[] args)
    {
        Coffee myCoffee = new Espresso();
        Console.WriteLine($"{myCoffee.GetDescription()} ${myCoffee.Cost()}");

        myCoffee = new Milk(myCoffee);
        Console.WriteLine($"{myCoffee.GetDescription()} ${myCoffee.Cost()}");

        myCoffee = new Sugar(myCoffee);
        Console.WriteLine($"{myCoffee.GetDescription()} ${myCoffee.Cost()}");

        myCoffee = new WhippedCream(myCoffee);
        Console.WriteLine($"{myCoffee.GetDescription()} ${myCoffee.Cost()}");

        // Output:
        // Espresso $1.99
        // Espresso, Milk $2.49
        // Espresso, Milk, Sugar $2.69
        // Espresso, Milk, Sugar, Whipped Cream $3.39
    }
}
```

### Summary

- **Step 1**: Define a Component interface or abstract class.
- **Step 2**: Create Concrete Components that implement the Component interface.
- **Step 3**: Create an abstract Decorator class that also implements the Component interface and holds a reference to a Component object.
- **Step 4**: Create Concrete Decorators that extend the Decorator class and add functionalities.
- **Step 5**: Use the decorators to dynamically add behaviors to the component.

By following these steps, you can implement the Decorator Pattern to add functionalities to objects dynamically, keeping your design flexible and adherent to the Open/Closed Principle. This approach helps in maintaining a clean and extendable codebase.