Thursday, February 16, 2012

Design Pattern : Decorator Pattern Implemetation

The main motivation before the decorator pattern is to be able to add data and behavior to objects dynamically
without relying on inheritance.

A decorator usually conforms to the interface of the component its decorating.
Lets see this with an example.

Am building a system that calculates the price of a pizza. I can have many toppings and the total price of
the pizza is calculated based on what toppings I pick. One way to do this would be to use inheritance and
class hierarchies like Pizza, CheesePizza, ChickenPizza etc…which can get very inflexible.

A better way is to implement this using decorators. Below PizzaWithCheese decorates
the Pizza and adds the price of cheese to the total and so does the PizzaWithChicken.
When executed you should see the following output:

Total for cheese pizza: 15
Total for chicken pizza: 16
Total for cheese + chicken pizza: 21

 class DecoratorPattern
    {
        private interface IPizza
        {
            int GetPrice();
        }
 
        private class Pizza : IPizza
        {
            public int GetPrice()
            {
                return 10;
            }
        }
 
        //Decorator 1
        private class PizzaWithCheese : IPizza
        {
            private IPizza _pizza;
            private int _priceofCheese;
 
            public PizzaWithCheese(IPizza pizza, int priceofCheese)
            {
                _pizza = pizza;
                _priceofCheese = priceofCheese;
            }
 
            public int GetPrice()
            {
                //get price of the base pizza and add price of cheese to it
                return _pizza.GetPrice() + _priceofCheese;
            }
        }
 
        //Decorator 2
        private class PizzaWithChicken : IPizza
        {
            private IPizza _pizza;
            private int _priceofChicken;
 
            public PizzaWithChicken(IPizza pizza, int priceofChicken)
            {
                _pizza = pizza;
                _priceofChicken = priceofChicken;
            }
 
            public int GetPrice()
            {
                //get price of the base pizza and add price of chicken to it
                return _pizza.GetPrice() + _priceofChicken;
            }
        }
 
 
        public static void Test()
        {           
            var pizzaWithCheese = new PizzaWithCheese(new Pizza(), 5);
            var pizzaWithChicken = new PizzaWithChicken(new Pizza(), 6);
 
            //pizza with chicken and cheese is easy to build now.
            //we can keep decotaring the base pizza with as many decorators as necessary at runtime
            var pizzaWithChickenAndCheese = new PizzaWithChicken(pizzaWithCheese, 6);
 
            Console.WriteLine("Total for cheese pizza: " + pizzaWithCheese.GetPrice());
            Console.WriteLine("Total for chicken pizza: " + pizzaWithChicken.GetPrice());
            Console.WriteLine("Total for cheese + chicken pizza: " + pizzaWithChickenAndCheese.GetPrice());
        }
    }
 
 Another Example

Introduction

Decorator pattern is a software design pattern where we can use to extend the functionality of the object run time. Decorator pattern attaches additional responsibility by decorating the other object by assigning an instance to similar base interface instance.

Here is the example of Coffe making system.
Class Diagram

First there is an interface Called ICoffee which every subclasses will implement this interface.

public interface ICoffee

{double Price();

string Ingrediants();

}

Next we will declare the basic implementation of the coffe class by implementing ICoffee Interface.
public class Coffee : ICoffee
{public double Price()
{return 3.5;
}public string Ingrediants()
{return "Simple Coffee";
}
}Next we will create a decorator base implementation by implementing the ICoffee interface. This class declare the ICoffee interface variable and accepts the instance ICoffee concrate instance object.
public class CoffeeDecorator : ICoffee
{protected ICoffee decCoffee;
public CoffeeDecorator(ICoffee coffee)
{
decCoffee = coffee;
}
public virtual double Price()
{return decCoffee.Price();
}public virtual string Ingrediants()
{return decCoffee.Ingrediants();
}}
We will implement the generalize version of the cofee classes.
public class Milk : CoffeeDecorator
{public Milk(ICoffee coffee)
base(coffee) { }
public override double Price()
{return base.Price() + .50d;
}public override string Ingrediants()
{return base.Ingrediants() + " + Milk Addedd";
}
}
public class Whip : CoffeeDecorator
{public Whip(ICoffee coffee)
base(coffee) { }
public override double Price()
{return base.Price() + .50d;
}public override string Ingrediants()
{return base.Ingrediants() + " + Whip Addedd";
}
}
public class Sprinkles : CoffeeDecorator
{public Sprinkles(ICoffee coffee)
base(coffee) { }
public override double Price()
{return base.Price() + .50d;
}public override string Ingrediants()
{return base.Ingrediants() + " + Sprinkles Addedd";
}
}Finally we will see how we can attach the additional functionality to the classes using decorator pattern.

class Program

{static void Main(string[] args)

{ICoffee coffee = new Coffee();Console.WriteLine("Price: " + coffee.Price() + " Ingrediants: " + coffee.Ingrediants());coffee = new Milk(coffee);Console.WriteLine("Price: " + coffee.Price() + " Ingrediants: " + coffee.Ingrediants());coffee = new Whip(coffee);Console.WriteLine("Price: " + coffee.Price() + " Ingrediants: " + coffee.Ingrediants());coffee = new Sprinkles(coffee);Console.WriteLine("Price: " + coffee.Price() + " Ingrediants: " + coffee.Ingrediants());Console.ReadLine();

}}
Output

 

 

.Net Framework Library Example

Similarly, in .net library, the following is one of the example where the decorator pattern is being used.
There is an abstract stream class is in .net library and there are set of classes designed aound the stream class. The BufferedStream & CryptoStream classes are the example of decorator pattern.
if you try to create an instance of the BufferedStream class then you see that it accepts the stream class instance in the contructor which means that bufferstream class add additional functionality to the stream class as BufferedStream and Stream class has the similar behaviour.
BufferedStream str=new BufferedStream(Stream stream);

 
Reference :
http://geekswithblogs.net/amaniar/archive/2012/02/10/a-simple-implementation-of-the-decorator-design-pattern-using-c-sharp.aspx
http://www.dotnetfunda.com/articles/article1541-how-and-where-microsoft-has-implemented-decorator-gof-design-patterns-in.aspx

No comments:

Post a Comment