Pages

Monday, 9 May 2016

Decorator design pattern

Decorator design pattern is used to enhance the functionality/responsibility of a particular object at run-time or dynamically.

The decorator pattern applies when there is a need to dynamically add as well as remove responsibilities to a class, and when sub-classing would be impossible due to the large number of sub-classes that could result.

Decorator design pattern is based on abstract classes and we derive concrete implementation from those classes.

At the same time other instance of same class will not be affected by this so individual object gets the new behavior.

Implementation of Decorator pattern:


Coffee making scenario
Coffee.java
/**
 * The interface Coffee defines the functionality of Coffee implemented by decorator
 * @author rajesh.dixit
 */
public interface Coffee {
     
    /** @return Returns the cost of the coffee.*/
    public double getCost();
   
    /** @return Returns the ingredients of the coffee */
    public String getIngredients();
}

SimpleCoffee.java
/**
 * Extension of a simple coffee without any extra ingredients
 * @author rajesh.dixit
 */
public class SimpleCoffee implements Coffee {

      @Override
      public double getCost() {
            return 1;
      }

      @Override
      public String getIngredients() {
            return "Coffee";
      }
}

CoffeeDecorator.java
/**
 * Abstract decorator class - note that it implementsCoffee interface
 * @author rajesh.dixit
 */
public abstract class CoffeeDecorator implements Coffee {
      protected final Coffee decoratedCoffee;

      public CoffeeDecorator(Coffee c) {
            this.decoratedCoffee = c;
      }

      /** Implementing methods of the interface.*/
      public double getCost() {
            return decoratedCoffee.getCost();
      }

      public String getIngredients() {
            return decoratedCoffee.getIngredients();
      }
}


/**
 * Decorator WithMilk mixes milk into coffee.
 * Note it extends CoffeeDecorator.
 * @author rajesh.dixit
 */
class WithMilk extends CoffeeDecorator {
      public WithMilk(Coffee c) {
            super(c);
      }

      /** Overriding methods defined in the abstract superclass*/
      public double getCost() {
            return super.getCost() + 0.5;
      }

      public String getIngredients() {
            return super.getIngredients() + ", Milk";
      }
}


/**
 * Decorator WithSprinkles mixes sprinkles onto coffee.
 * Note it extends CoffeeDecorator.
 * @author rajesh.dixit
 */
class WithSprinkles extends CoffeeDecorator {
      public WithSprinkles(Coffee c) {
            super(c);
      }

      public double getCost() {
            return super.getCost() + 0.2;
      }

      public String getIngredients() {
            return super.getIngredients() + ", Sprinkles";
      }
}

TestDecorator.java
public class TestDecorator {

      public static void main(String[] args) {
            Coffee c = new SimpleCoffee();
            print(c);

            c = new WithMilk(c);
            print(c);

            c = newWithSprinkles(c);
            print(c);
      }

      public static void print(Coffee c) {
            System.out.println("Cost: " + c.getCost() + "; Ingredients: "
                        + c.getIngredients());
      }
}

Output:
Cost: 1.0; Ingredients: Coffee
Cost: 1.5; Ingredients: Coffee, Milk
Cost: 1.7; Ingredients: Coffee, Milk, Sprinkles

Usage in JDK:
1. All subclasses of java.io.InputStream, OutputStream, Reader and Writer have a constructor taking an instance of same type.

2. java.util.Collections, the checkedXXX(), synchronizedXXX() and unmodifiableXXX() methods.

3. javax.servlet.http.HttpServletRequestWrapper and HttpServletResponseWrapper.

4. Graphical User Interface Frameworks
GUI toolkits use decoration pattern to add functionalities dynamically as explained before.

Reference:

No comments:

Post a Comment