Sunday, August 7, 2016

Decorator Pattern


Decorator Pattern can be used to add new functionality to an object at runtime. Decorator pattern falls under structural pattern of GOF (Gang of Four) patterns.

When to use –


Decorator pattern can be used when you want to extend or add any additional functionality to an object at run-time. This means user will decide or select some functionality which will be added to object dynamically. The main benefit of decorator pattern is that the existing class is not modified directly by adding any functionality to object. 

There are so many real world example of Decorator pattern available but in this article I would like to explain very simple and easy real life example of Decorator pattern. Now a days mobile devices are very common and anyone can buy any mobile device of any brand. You have also observed that some companies bring some attractive offers on festival time or on some special events. So in such offers companies are offering mobile devices at an attractive discount and also provides some freebies like Flip Cover, Bluetooth headset etc with mobile device. So in this example you can consider mobile device as original product and different offers as decorator of original product. Let's have a look on below example how we can implement this example with decorator pattern.

Major components of Decorator Pattern –


Component – This is an interface and contains members which is implemented by Concrete Component. Additional functionality to this type of object will be added dynamically.
Concrete Component – This is a class and implements Component interface.
Decorator – This is an abstract class which implements Component interface. This class also contains additional functionalities of decorator to be added dynamically to Component object.
Concrete Decorator – This is a class and inherits from Decorator abstract class.

Code –
//Component
public interface IMobile
{
    string ModelName();
    string CompanyName();
    double Price();
}
//ConcreteComponent
public class LG : IMobile
{
    public string CompanyName()
    {
        return "LG";
    }

    public string ModelName()
    {
        return "LG G Pro2";
    }

    public double Price()
    {
        return 25000;
    }
    public override string ToString()
    {
        return string.Format("Company : {0}, Model : {1}, Price : {2}", CompanyName(), ModelName(), Price());
    }
}
//ConcreteComponent
public class SAMSUNG : IMobile
{
    public string CompanyName()
    {
        return "Samsung";
    }

    public string ModelName()
    {
        return "Galaxy Note 5";
    }

    public double Price()
    {
        return 30000;
    }
    public override string ToString()
    {
        return string.Format("Company : {0}, Model : {1}, Price : {2}", CompanyName(), ModelName(), Price());
    }
}
//Decorator
public class OffersDecorator : IMobile
{
    protected IMobile iMobile;
    public OffersDecorator(IMobile mobile)
    {
        iMobile = mobile;
    }
    public virtual string CompanyName()
    {
        return iMobile.CompanyName();
    }

    public virtual string ModelName()
    {
        return iMobile.ModelName();
    }

    public virtual double Price()
    {
        return iMobile.Price();
    }
    public virtual double Discount { get; set; }
    public virtual string OfferName { get; set; }
    public virtual string Accessories { get; set; }
}
//ConcreteDecorator
public class DiwaliOffersDecorator : OffersDecorator
{
    public DiwaliOffersDecorator(IMobile mobile) : base(mobile)
    {

    }
    public override string CompanyName()
    {
        return iMobile.CompanyName();
    }
    public override string ModelName()
    {
        return iMobile.ModelName();
    }
    public override double Price()
    {
        return (iMobile.Price()- (iMobile.Price() * (Discount/100)));
    }
    public override string ToString()
    {
        return string.Format("Offer Applicable : {0}, Discount : {1}%,\nAdditional Accessories : {2},\nCompany : {3}, Model : {4}, Discounted Price : {5}", OfferName, Discount, Accessories, CompanyName(), ModelName(), Price());
    }
}
//ConcreteDecorator
public class SpecialOffersDecorator : OffersDecorator
{
    public SpecialOffersDecorator(IMobile mobile) : base(mobile)
    {

    }
    public override string CompanyName()
    {
        return iMobile.CompanyName();
    }
    public override string ModelName()
    {
        return iMobile.ModelName();
    }
    public override double Price()
    {
        return (iMobile.Price() - (iMobile.Price() * (Discount / 100)));
    }
    public override string ToString()
    {
        return string.Format("Offer Applicable : {0}, Discount : {1}%,\nAdditional Accessories : {2},\nCompany : {3}, Model : {4}, Discounted Price : {5}", OfferName, Discount, Accessories, CompanyName(), ModelName(), Price());
    }
}
//Client
class Program
{
    static void Main(string[] args)
    {
        //creating original product
        LG LgMobile = new LG();
        Console.WriteLine("Original Product");
        Console.WriteLine(LgMobile.ToString());
        Console.WriteLine("");
        //adding additional functionalities to original product via decorator
        DiwaliOffersDecorator diwaliOffers = new DiwaliOffersDecorator(LgMobile);
        diwaliOffers.Discount = 25;
        diwaliOffers.OfferName = "Diwali Bonanza Offer";
        diwaliOffers.Accessories = "Flip Cover";
        Console.WriteLine(diwaliOffers.ToString());
        Console.WriteLine("-".PadLeft(50,'-'));
           
        //creating original product
        SAMSUNG samsungMobile = new SAMSUNG();
        Console.WriteLine("Original Product");
        Console.WriteLine(samsungMobile.ToString());
        Console.WriteLine("");
        //adding additional functionalities to original product via decorator
        SpecialOffersDecorator specialOffers = new SpecialOffersDecorator(samsungMobile);
        specialOffers.Discount = 10;
        specialOffers.OfferName = "Special Offer";
        specialOffers.Accessories = "Bluetooth Headset";
        Console.WriteLine(specialOffers.ToString());
        Console.ReadLine();
    }
}

Output –



As you can see in above example, LG and Samsung mobile manufacturer has their mobile devices available in market and they want to sell them on different occasions with different offers like festival offer or some special offer but the original product will be the same. So the discount and additional accessories will be different based on offer and can be consider as a decorator of product. They want to keep repeating such offers multiple times in a year on different occasions. So you can attach any decorator with any mobile device based on offer. In above example, you can add as many mobile devices you want and also you can attach any mobile device with any offer (decorator) dynamically.

I hope you enjoy reading this article and helps you to know more about Decorator Pattern. Please leave your feedback in comments section below.


References –

See Also –

No comments:

Post a Comment