Quantcast
Channel: Java Logs » Niraj Singh
Viewing all articles
Browse latest Browse all 10

Decorator Pattern

$
0
0
Decorator Pattern is a structural Pattern. It is used to dynamically add or remove responsibilities from an object when sub-classing would result in creating unmanageable number of classes.

Classification – Structural Pattern.

Intent – Providing extra responsibility to an object at run-time.

Discussion – Extending behavior of a class can be done statically by inheritance.  But many times inheritance is not the best way to extend the behavior as it violates the Open Close Principle. Sub-classing also results in a more fragile code as and changes to super class may result in breaking all the subsequent sub classes.  The alternative to inheritance is composition which allows the object to be wrapped by one or more decorator objects. Decorator objects are of same type as original objects and works on composition and delegation.  Let see how decorator works using a class diagram.

Solution

decorator

decorator

Participants

  1. Component – Parent Interface for the class whose behavior is to be modified at runtime.
  2. ConcreteComponent – Main class whose behavior is to be modified at runtime.
  3. Decorator – Abstract class implementing Component  and also contains an instance of component.
  4. ConcreteDecorator – Extends decorator. We need to have as many decorators as there are number of behavior.

Main points

  1. Decorators implement the same interface as the original object.
  2. They have an instance of original object.
  3. They implement the same method which needs extra responsibility.
  4. They are wrapper around the original objects.
  5. They are composed of original object and other decorators. They use composition to change the behavior.
  6. They provide a way to follow Open Close Principle.

Example.

Consider a pizza shop which sells pizza with many different kind of toppings. The toppings are customizable and final price of pizza will depend on topping that are used. Now one way to calculate the cost of each combination will be to have a subclass for each of the pizza combination and implement the cost method for each combination. The drawbacks for above scenario.

  1. Lets say there are 20 combinations. Then combinations of all the components will be huge. So we have to write staggering number of classes.
  2. If someone wants double topping of a particular components the number of combination will become even more.
  3. Adding one new component will result in addition of many more classes.

Thus we see that sub-classing here is not an option. Let see how we can use Decorator for solving this.

  1. Create a Pizza interface with method cost() and description(aka component)
  2. Implement Pizza interface lets say we have Pan Pizza and classic hand tossed pizza. (aka ConcreteComponent)
  3. Create a PizzaDecorator abstract class which implements Pizza. Add a instance variable of type Pizza. (aka decorator)
  4. Extend PizzaDecorator with as many toppings you have and implement the cost and description methods (aka concrete decorator).

Let check out the code for more coherency.

Component

public interface Pizza {

    public double cost();
    public String description();
}

ConcreteComponents

public class ClassicPizza implements Pizza {
    @Override
    public double cost() {
        return 175;
    }

    @Override
    public String description() {
        return "This is classic hand tossed pizza";
    }
}

public class PanPizza implements Pizza {
    @Override
    public double cost() {
        return 200;
    }

    @Override
    public String description() {
        return "This is pan pizza";
    }
}

Decorator

public abstract class Toppings implements Pizza{
    public Pizza pizza;
}

ConcreteDecorator

public class Paneer extends Toppings{

    public Paneer(Pizza pizza){
          this.pizza = pizza;
    }
    @Override
    public double cost() {
        return pizza.cost() + 50;
    }

    @Override
    public String description() {
        return pizza.description() + " paneer";
    }
}

public class Cheese extends Toppings {

    public Cheese(Pizza pizza){
           this.pizza = pizza;
    }
    public double cost() {
        return pizza.cost() + 30;
    }

    @Override
    public String description() {
        return pizza.description() + " cheese ";
    }
}

public class Onion extends Toppings {
    public Onion(Pizza pizza){
           this.pizza = pizza;
    }
    public double cost() {
        return pizza.cost() + 15;
    }

    @Override
    public String description() {
        return pizza.description() + " onion ";
    }
}

public class Chicken extends Toppings{

    public Chicken(Pizza pizza){
        this.pizza = pizza;
    }
    @Override
    public double cost() {
        return pizza.cost() + 50;
    }

    @Override
    public String description() {
        return pizza.description() + " chicken";
    }
}

So here we are, we have all the components to create our own pizza as per our wish. Check out how the cost and description method of pizza are modified at runtime in our concrete decorators. So now lets see how our PizzaMachine looks

public static void main(String[] args){

        // i want classic pizza
        Pizza pizza = new ClassicPizza();

        //want double dose of cheese on it
        Cheese cheese = new Cheese(pizza);
        cheese = new Cheese(cheese);

        //want some chicken on it.
        Chicken chicken = new Chicken(cheese);

        //want some onion on it
        Onion onion = new Onion(chicken);

        System.out.println("Your pizza is ready");
        System.out.println("You have ordered a " + onion.description() + " pizza");
        System.out.println("Price of your pizza is : "  + onion.cost());
    }
}

So here we are, we have successfully created a PizzaMachine which calculates cost of Pizzas at run-time. We attained this by wrapping/decorating a Pizza Objects with all the toppings we required.

Famous example

In java IO streams use decorator patterns. We have a base class InputStream which is an abstract class.  Other classes FileInputStream, BufferedStream etc extends this class and keeps an instance of InputStream.

References

  1. http://www.tutorialspoint.com/design_pattern/decorator_pattern.htm
  2. http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition–which-one-should-you-choose-.html
  3. http://www.oodesign.com/decorator-pattern.html
  4. http://sourcemaking.com/design_patterns/decorator

Viewing all articles
Browse latest Browse all 10

Latest Images

Trending Articles



Latest Images