Decorator Design Pattern in C#

Decorator Design Pattern in C# with Examples

In this article, I am going to discuss the Decorator Design Pattern in C# with some examples. Please read our previous article where we discussed the Facade Design Pattern in C# with examples. The Decorator Design Pattern falls under the category of Structural Design Pattern. As part of this article, we are going to discuss the following pointers.

  1. What is the Decorator Design Pattern?
  2. Understanding the Decorator Design Pattern with a real-time example
  3. Implementing Decorator Design Pattern in C#
  4. Understanding the Class Diagram of the Decorator Design Pattern.
  5. When to use the Decorator Design Pattern in real-time applications?
What is the Decorator Design Pattern?

The Decorator Design Pattern allows us to dynamically add new functionalities to an existing object without altering or modifying its structure and this design pattern acts as a wrapper to the existing class.

This design pattern dynamically changes the functionality of an object at runtime without impacting the existing functionality of the objects. In short, this decorator design pattern adds additional functionalities to the object by wrapping it.

A decorator is an object that adds features to another object.

Let us understand the above explanation with an example. Please have a look at the following image. As shown in the below image, we have a circle object and that circle object is having a method called Draw. What the Draw method will do is it will draw a circle.

What is the Decorator Design Pattern?

Now I want to add some color to the circle object but I don’t want to change or alter the structure of the Circle object. Meaning I should not add any method to the circle object. So, how can I achieve this? I can achieve this very easily using the Decorator Design Pattern. So what I can do here is, I will introduce the CircleDecorator object which will wrap the circle object as shown in the below image. The CircleDecorator object also has the Draw method. What the Circle Decorator Draw method will do is, first it will call the Draw method of the Circle object so that it will draw the circle and then it will call the SetColor method of the CircleDecorator object to set the color of the circle.

Understanding the Decorator Design Pattern in C#

So, in this way, without affecting the structure of the Circle object, we can add new functionalities to the Circle object. Now, if you read the explanation again then you will understand the definition of Decorator Design Patter.

Note: The Decorator Design Pattern provides an alternative approach to inheritance for modifying the behavior of an object. When we use inheritance to extend the behavior of a class, then this takes place at compile time.

Real-time Example of Decorator Design Pattern:

Let us understand the decorator design pattern with one real-time example. Please have a look at the following image. On the left-hand side, you can see the car without any engine. Let say, I want to add either the Petrol engine or Diesel engine to this car. Then what I need to do is, I have to introduce the Car Decorator. What this Car Decorator will do is, it will add Engine to the Car. Let say I want to add a Petrol Engine then the Car Decorator will add the Petrol Engine to this car and return the car with a petrol engine. Suppose, I want to add Diesel Engine to this car, then the Car Decorator will add a Diesel engine to this car and return the car with the Diesel engine.

Real-time Example of Decorator Design Pattern

As per the Decorator Design Pattern, the work of decorator is to add new functionalities or behavior to an existing object without altering its structure. So, in this case, Car without an engine is the existing object. What the Car Decorator does is, it will Petrol Engine or Diesel Engine to the Car based on the requirement. So, I think this is one of the best real-time examples of the Decorator Design Pattern.

Implementing the Decorator Design Pattern in C#:

Let us implement the above-discussed car example using the Decorator Design Pattern in C# step by step. Once we implement the decorator design pattern then we will try to understand the class diagram of Decorator Design Pattern by comparing it to this example so that you can easily understand.

Step1: Creating the Car interface

Create an interface with the name ICar and then copy and paste the following code in it. This interface has one abstract method i.e. ManufactureCar and this method is going to be implemented by the concrete subclasses.

namespace DecoratorDesignPattern
{
    public interface ICar
    {
        ICar ManufactureCar();
    }
}
Step2: Creating Concrete Car

Create a class file with the name BMWCar and then copy and paste the following code in it. This is a concrete class and implements the ICar interface i.e. provide an implementation for the ManufactureCar method. What this ManufactureCar method will do is, it will manufacture Car Body, Boor, Wheels, and Glass. So, when we call this ManufactureCar method it returns the BMW car without an engine.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DecoratorDesignPattern
{
    public class BMWCar : ICar
    {
        private string CarName = "BMW";
        public string CarBody { get; set; }
        public string CarDoor { get; set; }
        public string CarWheels { get; set; }
        public string CarGlass { get; set; }
        public string Engine { get; set; }

        public override string ToString()
        {
            return "BMWCar [CarName=" + CarName + ", CarBody=" + CarBody + ", CarDoor=" + CarDoor + ", CarWheels="
                            + CarWheels + ", CarGlass=" + CarGlass + ", Engine=" + Engine + "]";
        }

        public ICar ManufactureCar()
        {
            CarBody = "carbon fiber material";
            CarDoor = "4 car doors";
            CarWheels = "6 car glasses";
            CarGlass = "4 MRF wheels";
            return this;
        }
    }
}
Step3: Creating Car Decorator

Create a class with the name CarDecorator and then copy and paste the following code in it. This is going to be an abstract class and it also implements the ICar interface i.e. the ManufactureCar method. We declare the ManufactureCar method as virtual and this is because it is going to be overridden by the child classes.

namespace DecoratorDesignPattern
{
    public abstract class CarDecorator : ICar
    {
        protected ICar car;
        public CarDecorator(ICar car)
        {
            this.car = car;
        }

        public virtual ICar ManufactureCar()
        {
            return car.ManufactureCar();
        }
    }
}
Step4: Creating Diesel Car Decorator

Create a class file with the name DieselCarDecorator and then copy and paste the following code in it. This is a concrete class and inherited from the CarDecorator abstract class. This class overrides the ManufactureCar method. What this ManufactureCar method will do is, it will add a diesel engine to the car and will return the BMW car with Diesel Engine.

using System;
namespace DecoratorDesignPattern
{
    public class DieselCarDecorator : CarDecorator
    {
        public DieselCarDecorator(ICar car) : base(car)
        {
        }

        public override ICar ManufactureCar()
        {
            car.ManufactureCar();
            AddEngine(car);
            return car;
        }

        public void AddEngine(ICar car)
        {
            if (car is BMWCar)
            {
                BMWCar BMWCar = (BMWCar)car;
                BMWCar.Engine = "Diesel Engine";
                Console.WriteLine("DieselCarDecorator added Diesel Engine to the Car : " + car);
            }
        }
    }
}
Step5: Creating Petrol Car Decorator

Create a class file with the name PetrolCarDecorator and then copy and paste the following code in it. It is the same as the DieselCarDecorator. This means it also inherited from the CarDecorator class and overrides the ManufactureCar method. The ManufactureCar method will add the Petrol engine to the car and it will return the BMW car with Petrol Engine.

namespace DecoratorDesignPattern
{
    class PetrolCarDecorator : CarDecorator
    {
        public PetrolCarDecorator(ICar car) : base(car)
        {
        }

        public override ICar ManufactureCar()
        {
            car.ManufactureCar();
            AddEngine(car);
            return car;
        }

        public void AddEngine(ICar car)
        {
            if (car is BMWCar)
            {
                BMWCar BMWCar = (BMWCar)car;
                BMWCar.Engine = "Petrol Engine";
                Console.WriteLine("PetrolCarDecorator added Petrol Engine to the Car : " + car);
            }
        }
    }
}
Step6: Client code

The client class contains the Main method. So, please modify the Main method as shown below. Here, first, we create an object of BMWCar and then call the ManufactureCar method which will create the car without an engine. Then we create the instance of DieselCarDecorator and pass the BMWCar instance as a parameter to the constructor. And when we call the ManufactureCar method of the DieselCarDecorator instance, then it will add Diesel Engine to the Car.

using System;
namespace DecoratorDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            ICar bmwCar1 = new BMWCar();
            bmwCar1.ManufactureCar();
            Console.WriteLine(bmwCar1 + "\n");

            DieselCarDecorator carWithDieselEngine = new DieselCarDecorator(bmwCar1);
            carWithDieselEngine.ManufactureCar();

            Console.WriteLine();

            ICar bmwCar2 = new BMWCar();

            PetrolCarDecorator carWithPetrolEngine = new PetrolCarDecorator(bmwCar2);
            carWithPetrolEngine.ManufactureCar();

            Console.ReadKey();
        }
    }
}

Output:

How to implement the Decorator Design Pattern in C#

Now I hope you understand the Decorator Design Pattern. So, let’s try to understand the class diagram and the different component or participant involved in the Decorator Design Pattern by comparing with our example.

Understanding the Class Diagram of the Decorator Design Pattern:

Let us understand the Class Diagram of the Decorator Design Pattern. Please have a look at the following image.

Class Diagram of Decorator Design Pattern

As shown in the above image, four components are involved in the Decorator Design Pattern. They are as follows:

Component:

This is an interface. In our example, it is the ICar interface. This interface contains members that are going to be implemented by the concrete component (in our example BMWCar) classes and decorator (in our example CarDecorator) classes.

ConcreteComponent:

This is going to be a concrete class. In our example, it is the BMWCar class. This class simply implements the Component interface.

Decorator:

This is an abstract class and in our example, it is the CarDecorator class. This class implements the Component (i.e. ICar) interface and contains a reference to a component instance (in our example it is the car variable). This class also acts as the base class for all decorators. The decorator is essentially wrapping the Component.

ConcreteDecoratorA / ConcreteDecoratorB:

These are concrete classes (in our example, it is the PetrolCarDecorator and DieselCarDecorator classes) and inherited from the Decorator (i.e. CarDecorator) abstract class. This class adds the additional responsibility (in our example adding engine) to the original component.

When to use the Decorator Design Pattern in real-time applications?

We need to use the Decorator Design Pattern in C# when 

  1. We want to add new functionalities to existing objects dynamically,  
  2. A class definition may be hidden or otherwise unavailable for subclasses.  

In the next article, I am going to discuss the Decorator Design Pattern Real-Time Example – Pizza in C#. Here, in this article, I try to explain the Decorator Design Pattern in C# step by step with some simple examples. I hope you understood the need and use of Facade Design Pattern in C#.

1 thought on “Decorator Design Pattern in C#”

Leave a Reply

Your email address will not be published. Required fields are marked *