Design Patterns Simplified: Part 10 (Decorator)

Before starting, I would request that you visit the previous articles on Design Patterns series:

I am here to continue the discussion around Design Patterns. Today we will go through one of the structural design pattern called Decorator. Before talking about its implementation let’s begin with defining it. As per GOF guys, Decorator pattern is defined as follows:

 “Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclass for extending functionality.”

Well! Let’s understand what they mean.

They mean if we want to dynamically add responsibility to any object, we can go for Decorator pattern instead of sub-classing. Sub-classing has been the usual way to handle any added behavior however it becomes messy and difficult to maintain when dealing with multiple sub-classes. On the other hand, decorator pattern provides easy way to handle not just the multiple sub-classes but also their combinations.

Decorator pattern also enforces “Open-Closed” principle which is one of the SOLID design principle. We will talk about SOLID principle in future articles, however in short, Open-Closed principle suggests that classes should be open to extend and closed to modification.

How Decorator pattern works

Decorator pattern has four key elements as in the following.
  • Component: This is an interface of the object in which we want to add dynamic behavior.
  • ConcreateComponent: This is a concreate implementation of Component.
  • Decorator: Typically abstract class that defines the dynamic behavior. It also implements Component
  • ConcreateDecorator: Concreate implementation of Decorator. Each dynamic functionality implements its own ConcreateDecorator.

We will understand this by simple example.

Let’s start by creating component and take the similar vehicle example we took in previous articles.

  1. ///<summary>    
  2. /// The component    
  3. ///</summary>    
  4. public interface IVehicle    
  5. {    
  6.     string GetBrand();    
  7.     string GetModel();    
  8.     int GetPrice();    
  9. }   
Now let’s define ConcreateComponent classes. Here we will define two such classes.
  1. ///<summary>    
  2. /// The concrete component    
  3. ///</summary>    
  4. public class MarutiCar: IVehicle     
  5. {    
  6.     public string GetBrand()     
  7.     {    
  8.         return "Maruti";    
  9.     }    
  10.     
  11.     public string GetModel()     
  12.     {    
  13.         return "Swift VXI";    
  14.     }    
  15.     
  16.     public int GetPrice()     
  17.     {    
  18.         return 610000;    
  19.     }    
  20. }    
  21.     
  22. ///<summary>    
  23. /// The concrete component    
  24. ///</summary>    
  25. public class HyundaiCar: IVehicle    
  26. {    
  27.     public string GetBrand()     
  28.     {    
  29.         return "Hyundai";    
  30.     }    
  31.     
  32.     public string GetModel()    
  33.     {    
  34.         return "Grand i10 Magna";    
  35.     }    
  36.     
  37.     public int GetPrice()    
  38.     {    
  39.         return 540000;    
  40.     }    
  41. }    
Now time has come to define Decorator class. It implements Component interface and acts as a base class for dynamic behaviors. 
  1. ///<summary>    
  2. /// The Decorator abstract class    
  3. ///</summary>    
  4. public abstract class VehicleDecorator: IVehicle     
  5. {    
  6.     private IVehicle _vehicle;    
  7.     protected VehicleDecorator(IVehicle vehicle)     
  8.     {    
  9.         _vehicle = vehicle;    
  10.     }    
  11.     public string GetBrand()     
  12.     {    
  13.         return _vehicle.GetBrand();    
  14.     }    
  15.     
  16.     public string GetModel()    
  17.     {    
  18.         return _vehicle.GetModel();    
  19.     }    
  20.     
  21.     public int GetPrice()    
  22.     {    
  23.         return _vehicle.GetPrice();    
  24.     }    
  25. }   
Good so far!! Now design the concreate decorator classes to handle dynamic behavior as in the following.
  1. public class DiwaliOffer: VehicleDecorator    
  2. {    
  3.     public DiwaliOffer(IVehicle vehicle): base(vehicle) {}    
  4.     
  5.     public int PercentDiscount = 20;    
  6.     public int NewPrice()    
  7.     {    
  8.         return base.GetPrice() * (100 - PercentDiscount) / 100;    
  9.     }    
  10. }    
  11.     
  12. public class HoliOffer: VehicleDecorator    
  13. {    
  14.     publi cHoliOffer(IVehicle vehicle): base(vehicle) {}    
  15.     
  16.     public int PercentDiscount = 15;    
  17.     public int NewPrice()    
  18.     {    
  19.         return base.GetPrice() * (100 - PercentDiscount) / 100;    
  20.     }    
  21. }  
As you can sense that we have added two dynamic classes to handle offers during Diwali and Holi. There could be multiple such classes to handle various occasions.

Setup is ready now. Let’s use them in client and see the action.
  1. Console.Title = "Decorator pattern demo";    
  2. MarutiCar mCar = new MarutiCar();    
  3. Console.WriteLine("{0} {1} Regular price: {2}", mCar.GetBrand(), mCar.GetModel(), mCar.GetPrice());    
  4.     
  5. //Diwali Offer    
  6. Diwali OfferdOffer = newDiwaliOffer(mCar);    
  7. Console.WriteLine("{0} {1} Diwali price: {2} after discount of {3} percent", mCar.GetBrand(), mCar.GetModel(), dOffer.NewPrice(), dOffer.PercentDiscount);    
  8.     
  9. //Holi Offer    
  10. HoliOffer hOffer = new HoliOffer(mCar);    
  11. Console.WriteLine("{0} {1} Holi price: {2} after discount of {3} percent", mCar.GetBrand(), mCar.GetModel(), hOffer.NewPrice(), hOffer.PercentDiscount);   
Output:

output
  1. HyundaiCar mCar2 = new HyundaiCar();  
  2. Console.WriteLine("{0} {1} Regular price: {2}", mCar2.GetBrand(), mCar2.GetModel(), mCar2.GetPrice());  
  3. //Diwali Offer  
  4. DiwaliOffer dOffer2 = new DiwaliOffer(mCar2);  
  5. Console.WriteLine("{0} {1} Diwali price: {2} after discount of {3} percent", mCar2.GetBrand(), mCar2.GetModel(), dOffer2.NewPrice(), dOffer2.PercentDiscount);  
  6. //Holi Offer  
  7. HoliOffer hOffer2 = new HoliOffer(mCar2);  
  8. Console.WriteLine("{0} {1} Holi price: {2} after discount of {3} percent", mCar2.GetBrand(), mCar2.GetModel(), hOffer2.NewPrice(), hOffer2.PercentDiscount);
Output:

output

You can also refer the code in the attached sample.

To summarize, decorator pattern can be used when we want to add dynamic behavior or functionality to the existing objects and also without affecting the bases classes.

Hope you have liked the article. Look forward for your comments/suggestions.
 
Read more articles on Design Patterns:

X

Build smarter apps with Machine Learning, Bots, Cognitive Services - Start free.

Start Learning Now