Sunday, August 09, 2009

 
Let us look into a pattern which will help us learn how to decorate our classes at runtime using a form of object composition. Yes, we will talk about Decorator Pattern today. It is influenced by the design principle which says "Classes should be open for extension, but closed for modification." That is, by applying this pattern our classes need not be modified for extension. Let us now jump into a real time example.

Let us say we got an offer to develop an object oriented system for a fastfood chain. The system has to calculate the price for each order that is placed at the counter. This system will be installed on the macros placed at the counter.
This may sound simple, but the issue is there are N number of combination for an order. For analyzing this requirement further let us track few of the orders to understand the combination.

Order No. 1: One Turkey Breast + without cheese + with dark chocolate toppings.
Order No. 2: One Oven Roasted Chicken Breast + with extra cheese + dark chocolate topping.
Order No. 3: One Black Forest Ham + with extra cheese + fruit cream topping.

If we see orders above, you would see that each order is different and each person could choose any one ham and any combination of toppings out of given list of toppings. The good thing is that we have a list of hams and a list of toppings.

Now can you think of an object oriented design to solve this?

Well, let us try solving this with our conventional inheritance patterns.

Solution 1: We could create one abstarct class named Burger with an abstract method named Price() and specific classes dedicated to various combination of orders possible. Each such order implementing its Price() method to calculate the price for the order. But, as you might have already realized it is not a clean solution. It has too many disadvantages like it leads to class explosion, next, each time a new ham or topping is added to the menu it leads to changing the combinations, which leads to rewriting code and biggest disadvantage is that when ever a price change for any one items, all methods will have to undergo modifications. Well, in all a bad design.

Solution 2: We continue to have this abstract class Burger with properties to identify toppings like extra cheese, chocolate topping etc. That is, attribute could be bIsCheese, bIsChocolate. And setter methods to set properties to identify the toppings. The Price method now is no more abstract. The Price method of Burger class calculates price based on properties set. And the concrete classes like TurkeyBreast or OvenRoastedChickenBreast overrides the Price() method of parent class (Burger). The Price() method calls parent Price to get the Price for toppings and then adds its specific Price for the Ham.
Again not a clean solution.
OK, now we are sure that such solutions, using inheritance is not a feasible solution. Let us try now applying object combination.

Solution 3: Applying Decorator Pattern:

Let us apply decorator pattern which allow building order with combination of various items at run time. Let us see what is decorator pattern first.
The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub classing for extending functionality.

Now let us apply this to our problem. To do this we will define an interface named Burger. This will be implemented by TurkeyBreastHam, OvenRoastedChickenBreastHam and BlackForestHam. The Price() method of each of these classes will return the Price of its own. This interface Burger, is also implemented by abstract class, which will be responsible for applying decoration to our class. This class is named ToppingsDecorator. It has an abstract method named Price(). The reason behind its implementing the interface Burger is to apply same type as that of the objects to be decorated. The decorator should of same type as that of the object being decorated.

Now each of out Toppings viz., DarkChocolate, Cheese and FruitCream will inherit the abstract class ToppingsDecorator. It has an reference to Burger as an attribute, which gets initialized by its constructor.

Let us see the class diagram:



The Price() method will have following definition:

return 0.30 + objBurger.Price();

i.e., it returns the addition of its own price and add Price of the Burger it decorates.

The complete class definition for some of the classes are as follows:

public class TurkeyBreastHam implements Burger
{
public double Price()
{
return 0.99;
}
}

public abstract class ToppingsDecorator implements Burger
{
public abstract double Price();
}

public class DarkChocolate extends ToppingsDecorator
{
Burger objBurger;

public DarkChocolate(Burger objBurg)
{
objBurger = objBurg;
}

public double Price()
{
return 0.30 + objBurger.Price();
}
}

Let us see one of the implementation to understand it better

public class FastFoodSystems
{
public static void main(String args[])
{
Burger objBurger = new TurkeyBreastHam(); //order a TurkeyBreastHam
objBurger = new Cheese(objBurger); // on this order a Cheese toppings
objBurger = new DarkChocolate(objBurger); /// and then a DarkChocolate Topping
System.out.println("The Total Price for the order is " + objBurger.Price()); //the price of order TurkeyBreastHam + Cheese + Dark Chocolate
}
}

So, this is our solution. It is clean and a scalable solution. We need not modify the class to add new items in menu, we simply add new classes.

That's all for the day. Do let me know what you feel about it.

Bye for now....

Labels: , ,


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?