Wednesday, February 9, 2011

Decorator Pattern


Decorator Pattern 
In Design Patterns, the authors define the Decorator pattern as:

Attach additional responsibilities to an object dynamically.

Decorators provide a flexible alternative to subclassing for extending functionality.

In the Decorator pattern, a decorator object is wrapped around the original object. This is typically achieved having the original object as a member of the decorator, with the decorator forwarding the requests to the original object and also implementing the new functionality.

Usage Scenarios
  • Add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects.
  • Be able to withdraw responsibilities
    For example: The java.util.Collections.unmodifiableCollection(Collection) removies the ability to change a given collection by wrapping it with a decorator that throws an UnSupportedException when you try to modify the Collection.
  • When extension by subclassing is impractical, such as when a large number of independent extensions produce an explosion of subclasses to support every combination. Or a class is unavailable for subclassing.
Design
Here is the UML diagram of the Decorator pattern followed by a description of the various involved components.
  • Component: Defines the interface for objects that can have responsibilities added to them dynamically.
  • ConcreteComponent: Defines an object to which additional responsibilities can be attached.
  • Decorator: Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
  • ConcreteDecorator: Adds responsibilities to the component.
Implementing Decorator Pattern
The following is sample implementation of the Decorator pattern in Java.
  1. The Component Interface
interface Breakfast {
   public double cost();
   public String getDescription();
}
Component.java
  1. The Concrete Component
public class Dosa implements Breakfast{
 
  public double cost() {
         return 15.0;
  }
  public String getDescription() {
         return "Dosa";
  }
}
Dosa Rs: 15



public class Idli implements Breakfast {

  public double cost() {
         return 10.50;
  }

  public String getDescription() {
         return "Idly";
  }
}
Idli Rs: 10.50

ConcreteComponent.java
  1. The Decorator
public interface Decorator extends Breakfast {

  public void addedBehavior();

}
Decorator.java
Note: The decorator interface has to conform to the component interface, hence it extends Component.

  1. The Concrete Decorator
public class MasalaDecorator implements Decorator {
  Breakfast breakfast;

  public MasalaDecorator(Breakfast breakfast) {
         this.breakfast = breakfast;
  }

  public String getDescription() {
         return breakfast.getDescription() + "with Masala Decoration";
  }

  public double cost() {
         return breakfast.cost() + 5.50;
  }

  public void addedBehavior() {
         System.out.println("Do additional stuff");
  }
}
Masala Decoration Rs: 5.50


public class OnionDecorator implements Decorator {
  Breakfast breakfast;

  public OnionDecorator(Breakfast breakfast) {
         this.breakfast = breakfast;
  }

  public String getDescription() {
         return breakfast.getDescription() + " with Onion Decoration";
  }

  public double cost() {
         return breakfast.cost() + 3.50;
  }

  public void addedBehavior() {
         System.out.println("Do additional stuff");
  }
}
Onion Decortion Rs: 3.50

ConcreteDecorator.java


  1. The Client: Feeling Hungry!!! Time for Breakfast

public class BreakfastMenu {

  public static void main(String[] args) {

         // without adding decorators
         Breakfast menu1 = new Dosa();
         System.out.println(menu1.getDescription() + " Rs. " +       menu1.cost());

         Breakfast menu2 = new Idli();
         System.out.println(menu2.getDescription() + " Rs. " + menu2.cost());

         // adding decorators to Dosa
         Breakfast menu3 = new MasalaDecorator(new Dosa());
         System.out.println(menu3.getDescription() + " Rs. " + menu3.cost());
Dosa with Masala Decoration Rs: 20.50


         Breakfast menu4 = new OnionDecorator(new Dosa());
         System.out.println(menu4.getDescription() + " Rs. " + menu4.cost());
Dosa with Onion Decoration Rs: 18.50

         Breakfast menu5 = new MasalaDecorator(new OnionDecorator(new Dosa()));
         System.out.println(menu5.getDescription() + " Rs. " + menu5.cost());
Dosa with Masala and Onion Decoration Rs: 24 


         // adding decorators to Idli
         Breakfast menu6 = new MasalaDecorator(new Idli());
         System.out.println(menu6.getDescription() + " Rs. " + menu6.cost());
Idli with Masala Decoration Rs: 16


         Breakfast menu7 = new OnionDecorator(new Idli());
         System.out.println(menu7.getDescription() + " Rs. " + menu7.cost());
Idli with Onion Decoration Rs: 14

         Breakfast menu8 = new MasalaDecorator(new OnionDecorator(new Idli()));
         System.out.println(menu8.getDescription() + " Rs. " + menu8.cost());
Idli with Masala and Onion Decoration  Rs: 19.5

  }
}
Client.java



Rates for the breakfast we ordered
Dosa Rs. 15.0
Idly Rs. 10.5
Dosa with Masala Decoration Rs. 20.5
Dosa with Onion Decoration Rs. 18.5
Dosa with Onion Decoration with Masala Decoration Rs. 24.0
Idly with Masala Decoration Rs. 16.0
Idly with Onion Decoration Rs. 14.0
Idly with Onion Decoration with Masala Decoration Rs. 19.5    
 

Highlights of Decorator Pattern 

·         You can wrap a component with any number of decorators.
·         The decorator adds its own behavior either before and/or after delegating to the object it decorates to do the rest of the job.
·         Objects can be decorated at any time, so we can decorate objects dynamically at runtime with as many decorators as we like.
·         Decorators can extend the state of the component.
·         Decorators can add new methods. however new behavior is typically added by doing computation before or after an existing method in the component.
·         In our designs we should allow behavior to be extended without the need to modify existing code.
·         Composition and delegation can often be used to add new behaviors at runtime.
·         The Decorator Pattern provides an alternative to sub classing for extending behavior.
·         Decorator classes mirror the type of the components they decorate. (In fact, they are the same type as the components they decorate, either through inheritance or interface implementation.)
·         Decorators change the behavior of their components by adding new functionality before and/or after (or even in place of) method calls to the component.
·         Decorator is designed to let you add responsibilities to objects without sub classing.
·         Decorator lets us change the skin of an object. Strategy lets us change the guts.[GoF, p184]

Disadvantage : 
Only disadvantage is code maintenance can be a problem as it provides the system with a lot of similar looking small objects(each decorator). Decorators can result in many small objects in our design, and overuse can be complex.

14 comments:

  1. hey whts dis?
    java dosa

    ReplyDelete
  2. its cool anyways, engineer the backbone of india

    ReplyDelete
  3. Java has all the flavors of Dosa's and Idli's
    Enjoy Design Patterns...

    ReplyDelete
  4. For design patterns and principles, refer http://www.oodesign.com/
    Best of luck

    ReplyDelete
  5. Kya Program hei yaar sab syntax error aa rahe hein

    ReplyDelete
  6. Error toh nahi aana chiye...I can send you .java files also..

    ReplyDelete
  7. Its working fine

    ReplyDelete
  8. We loved the examples its quite interesting. the name make sense Sleeping with JAVA. Awesom .

    ReplyDelete
  9. Indeed your example was yummy :) What is most important point with decorator is that it affect only individual object and not all object which itself a big control and flexibility inheritance doesn't offer. See here for What is decorator pattern in Java with Example.

    ReplyDelete
  10. Main benefit of decorator is that it affect only individual object and not all object which itself a big control and flexibility inheritance doesn't offer. See here for another example of decorator pattern in Java.

    ReplyDelete