Decorator Pattern In C#
Tags: beginners, programming, tutorial, csharp
Published: 2022-09-01 20:30:24

_Originally posted [here](https://dfordebugging.wordpress.com/2022/09/01/decorator-pattern-in-c/)_

The **Decorator** is a structural design pattern that lets us attach new behaviours to objects by placing these objects inside special wrappers. These wrappers add the desired behaviour without modifying the original code.

The **Decorator** is a handy tool when we have some object that we want to enhance with additional behaviours. Still, we are either unwilling or unable to change its internal workings. With this pattern, we can wrap the object in a specialized wrapper and implement the functionality in the wrapper.

You can find the example code of this post, on [Github](https://github.com/Kalkwst/DesignPatterns)

## Conceptualizing the Problem

Imagine that we have a notification library which lets us notify a user about deployment events.

The initial version of the library is based on a `Notifier` class that has a few fields such as a list of email addresses, a constructor and a single `Notify` method. The `Notify` method accepts a message argument from the client and sends it to a list of emails, provided via the `Notifier`'s constructor. Some other application acts as a client and will configure the `Notifier` once, and then use it each time something important happens during the deployment workflow.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fpva3vjs4hjrmcj2ccl9.PNG)

The library worked perfectly for some time, but then disaster struck. During a nightly release, the build failed, and the emails were sent but there wasn't anyone to address the issue. After all, most people don't check their emails in the middle of the night.

Now the users require much more than just email notifications. Many of them would like to receive an SMS notification about critical issues. Others would like Microsoft Teams notifications, and the DevOps teams would love to get Slack notifications for some reason or another.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nh9h65uoxyf1l7gxlx6s.PNG)

No problem there! We can extend the `Notifier` class and add the additional notification methods into new subclasses. Now the client can instantiate the appropriate notification class and use it for further notification.

But then someone asked the million-dollar question. "Why can't you use several notifications at once? If the boat is sinking you'd probably want to be informed through every channel".

Keeping with our previous solution, we can address the problem by extending the `Notifier` class with special subclasses that combine several notification methods in one class. Time for some simple math now. Each notification method can either exist or not exist in a subclass. Thus there are two states for the existence of a notification method. We currently have 3 different notification methods. So there are 2 to the power of 3 different combinations of subclasses or 8 classes. If we add another notification method we will have 2 to the power of 4 different subclasses, or 16 different classes altogether. It becomes apparent that this approach will bloat the code exponentially. 

Extending a class is the first thing that comes to mind when we need to alter an object's behaviour. However, there are some issues with Inheritance.

- Inheritance is **static**. We can't alter the behaviour of an existing object at *runtime*. We can only replace the instance with another that's created by a different subclass.
- Subclasses can have just one parent class. In C#, inheritance doesn't let a class inherit behaviours from multiple classes simultaneously.

One of the ways to overcome these caveats is by using *Aggregation* or *Composition* instead of *Inheritance*. Both of these alternatives are almost identical. An instance has a *reference* to another instance and **delegates** some work, whereas, with inheritance, the instance itself **executes** that work, *inheriting* the behaviour from its parent.

With this new approach, we can easily substitute the linked object with another changing the behaviour of the container at runtime. Aggregation and Composition are key techniques behind many design patterns, including the **Decorator**.

A **Decorator**. also known as a **Wrapper**, can be linked with some *target* object. The wrapper can delegate all requests it receives to the target. However, the wrapper can alter the result by either processing the request **before** it is sent to the target or altering the response **after** the target returns a result.

## Structuring the Decorator Pattern

The following diagram demonstrates how the Decorator pattern works.

![High Level Flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hf23q63z596rwab8ywji.PNG)

1. The application makes a request and the decorator class intercepts it.
2. The decorator class can pre-process the request before passing it to the wrapped class.
3. The wrapped class performs its functionality, as usual, unaware of the decorator class.
4. The decorator class can post-process the response before passing it to the application.
5. The decorator returns the result to the original caller.

In its base implementation, the Decorator pattern has four participants:

- **Component**: The **Component** declares the common interfaces for both wrappers and wrapped objects.
- **Concrete Components**: The **Concrete Component** is the class of objects that will be wrapped. It defines the original behaviour that can be altered by the decorators.
- **Base Decorator**: The **Base Decorator** references the wrapped object. The base decorator delegates all operations to the wrapped object.
- **Concrete Decorators**: The **Concrete Decorator** define additional behaviours that can be added to **Concrete Components** dynamically. 
- **Client**: The **Client** can wrap components in multiple layers of decorators, as long as it works with the objects via a shared interface.

![Decorator Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1sng3f18r295ma0mrr55.PNG)

To demonstrate how the Decorator pattern works, we will open a fancy farm-to-fork restaurant.

The idea behind the restaurant is that make dishes from ingredients directly acquired from the producer. This means that some dishes may be marked as *sold out* since the farm can produce only so many ingredients. 

To start, we will implement our **Component** participant, which is our abstract `Dish` class:

```csharp
namespace Decorator.Components
{
    /// <summary>
    /// The abstract Component class
    /// </summary>
    public abstract class Dish
    {
        public abstract void Display();
    }
}
```

We also need a couple of **ConcreteComponent** participant classes representing the individual dishes our restaurant can serve. These classes only care about the ingredients of a dish and not the number of dishes available. This is the responsibility of the **Decorator**.

```csharp
namespace Decorator.Components
{
    /// <summary>
    /// A ConcreteComponent class
    /// </summary>
    public class Salad : Dish
    {
        private readonly string _veggies;
        private readonly string? _cheeses;
        private readonly string? _dressing;

        public Salad(string veggies, string? cheeses, string? dressing)
        {
            _veggies = veggies;
            _cheeses = cheeses;
            _dressing = dressing;
        }

        public override void Display()
        {
            Console.WriteLine("\nSalad:");
            Console.WriteLine($" Veggies: {_veggies}");
            Console.WriteLine($" Cheeses: {_cheeses}");
            Console.WriteLine($" Dressing: {_dressing}");
        }
    }
}
```

```csharp
namespace Decorator.Components
{
    /// <summary>
    /// A ConcreteComponent class
    /// </summary>
    public class Pasta : Dish
    {
        private readonly string _pasta;
        private readonly string _sauce;

        public Pasta(string pasta, string sauce)
        {
            _pasta = pasta;
            _sauce = sauce;
        }

        public override void Display()
        {
            Console.WriteLine("\nPasta: ");
            Console.WriteLine($" Pasta: {_pasta}");
            Console.WriteLine($" Sauce: {_sauce}");
        }
    }
}
```

Now, we need to keep track of whether a dish is available. To do this we will first implement an `AbstractDecorator`  class which is our **Decorator** participant.

```csharp
namespace Decorator.Decorators
{
    /// <summary>
    /// The Abstract Base Decorator
    /// </summary>
    public abstract class AbstractDecorator : Dish
    {
        protected Dish _dish;

        protected AbstractDecorator(Dish dish)
        {
            _dish = dish;
        }

        public override void Display()
        {
            _dish.Display();
        }
    }
}
```

Finally, we need a **ConcreteDecorator** participant, to keep track of how many of the dishes have been ordered. This is the role of the `AvailabilityDecorator`.

```csharp
namespace Decorator.Decorators
{
    public class AvailabilityDecorator : AbstractDecorator
    {
        public int AvailableItems { get; set; }
        protected List<string> customers = new();

        public AvailabilityDecorator(Dish dish, int available) : base(dish)
        {
            AvailableItems = available;
        }

        public void OrderItem(string name)
        {
            if (AvailableItems > 0)
            {
                customers.Add(name);
                AvailableItems--;
            }
            else
                Console.WriteLine($"\nNot enough ingredients for {name}'s dish");
        }

        public override void Display()
        {
            base.Display();

            foreach(string customer in customers)
                Console.WriteLine($"Ordered by {customer}");
        }
    }
}
```

The last step is to set up the `Main` method. First, we will define a set of dishes, and then decorate them so they can keep track of their availability. Finally, we will order the dishes.

```csharp
Salad caesarSalad = new("Crisp Romaine Lettuce", "Parmesan Cheese", "Homemade Caesar Dressing");
caesarSalad.Display();

Pasta fetuccine = new("Homemade Fetuccine", "Creamy Garlic Alfredo Sauce");
fetuccine.Display();

Console.WriteLine("\nChanging availability of the dishes");

AvailabilityDecorator caesarAvailability = new(caesarSalad, 3);
AvailabilityDecorator pastaAvailability = new(fetuccine, 4);

caesarAvailability.OrderItem("Marion");
caesarAvailability.OrderItem("Thomas");
caesarAvailability.OrderItem("Imogen");
caesarAvailability.OrderItem("Jude");

pastaAvailability.OrderItem("Marion");
pastaAvailability.OrderItem("Thomas");
pastaAvailability.OrderItem("Imogen");
pastaAvailability.OrderItem("Jude");
pastaAvailability.OrderItem("Jacinth");

caesarAvailability.Display();
pastaAvailability.Display();

Console.ReadLine();
```

The output of our application will be the following:

![Decorator Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y56cnclyd710xi92fm95.PNG)

## The Problem of Fat Decorators
Decorators are all about composability. This means that the reused class is not inherited but wrapped by decorator classes. This comes with a caveat. The decorator **does not inherit** the `public` interface of the reused class, but needs to **explicitly implement** every method of the interface. Creating and maintaining all of these methods can add quite an overhead. 

While there are some development tools like ReSharper that can help with handling all of those methods, the responsibility of maintenance still lies on the developer.

# Pros and Cons of Decorator Pattern
|||
|:--|:--|
|✔ We can extend an object's behaviour without altering its source code|❌ It's hard to remove a wrapper from a wrapper stack|
|✔ We can extend an object's behaviour without creating a new subclass.|❌ It's hard to implement decorators in such a way that will not depend on the order of decorators in a wrapper stack.|
|✔ We can combine multiple decorators to add several behaviours to an object|❌ Fat decorators might have to implement several methods that will not use|
|✔ We can divide a monolithic class into multiple classes, each with its behaviour, thus satisfying the *Single Responsibility Principle*|❌ The initial configuration of layers can look pretty ugly and might be hard to maintain|

# Relations with Other Patterns

- The **Adapter** and **Decorator** work in a similar way. However, the **Adapter** changes the interface of an existing object, while the **Decorator** enhances an object without changing its interface. In addition, the *Decorator* supports **recursive** composition, which is impossible when using the *Adapter*. Finally the **Adapter** provides a different interface for the wrapped object, while the **Decorator** provides it with an enhanced interface.
- The **Chain of Responsibility** and **Decorator** have similar class structures. Both interfaces rely on recursive composition. However, there are some differences. The *CoR* handler can execute arbitrary operations without dependence on other handlers in the chain. On the other hand, a *Decorator* can extend the object's behaviour while keeping it consistent with the base interface. Moreover, decorators aren't allowed to break the flow of the request.
- The **Composite** and **Decorator** patterns have a similar structure since both rely on recursive composition. A *Decorator* is like a *Composite* but only has one child component. Also the *Decorator* adds additional responsibilities to the wrapped object, while *Composite* just sums up its children's results.
- The **Decorator** and **Proxy** have similar structures, but very different intents. Both patterns are built on the composition principle. However a *Proxy* usually manages the life cycle of its service object on its own, whereas the composition of the *Decorator* is always controlled by the client.

# Final Thoughts

In this article, we have discussed what is the Decorator pattern, when to use it and what are the pros and cons of using this design pattern. We then examined what is a fat decorator and how the Decorator pattern relates to other classic design patterns. 

It's worth noting that the Decorator pattern, along with the rest of the design patterns presented by the Gang of Four, is not a panacea or a be-all-end-all solution when designing an application. Once again it's up to the engineers to consider when to use a specific pattern. After all these patterns are useful when used as a precision tool, not a sledgehammer.