Decorator Pattern

Decorator pattern allows to add new functionality an existing object without altering its structure. Decorators provide a flexible alternative to subclassing for extending functionality. Subclassing adds behavior at compile time, and the change affects all
instances of the original class; decorating can provide new behavior at runtime for individual objects. The Decorator Design Pattern simplifies code because you add functionality using many simple classes. Also, rather than rewrite old code you can extend it
with new code and that is always good.

Lets take an example of a Coffee house offering many beverages.

Approach 1 – was to make a abstract Beverage class having description flied with getter and an abstract cost() method. Now the different kind of beverages will extend this class like Espresso, Decaf, HouseBlend etc and set the description and implement the cost() method. Now each coffee can have condiments like Whip, Mocha, Soy, Steamed Milk etc. In order to accomodate, they needed to create all possible classes like HouseBlendWithSoy, HouseBlendWithWhip, HouseBlendWithSoyWhip etc. This resulted in creating a huge number of classes, obiviously difficult to manage.

DecoratorWrongApproach1

Approach 2 – Another way is to have boolean variables for Whip, Soy, Mocha and other possible condiments in the beverage class. This beverage class calucates the cost by these valuse in its cost() methos. Now subclasses like HouseBlend, Espresso extend this and set these boolean values and override cos()t method. In this overriden method they first call the super class cost() methos before adding to the cost. This way the classes created will be less. But this approach has its own flaws like – New addition of condiments will force Beverage class to change, new beverage like lice tea will still have whip etc when they actually dont need it.

DecoratorWrongApproach2

Decorator way – If the custor wants HouseBlend with Mocha and Whip – Take a HouseBlend object, decorate it with Mocha object, decorate this with Whip object and then call the cost() method on the final object that will give the toatl cost. basic UML diagram of the decorator pattern is as follows:

DecoratorApproach1

Above, the ConcreteComponent will be our Espresso, HouseBlend, Decaf classes. ConcreteDecorator will be our Soy, Whip, Mocha classes. We’re subclassing the abstract class Beverage in order to have the correct type, not to inherit its behavior. The behavior comes in through the composition of decorators with the base components as well as other decorators.We can implement new decorators at any time to add new behavior. If we relied on inheritance, we’d have to go in and change existing code any time we wanted new behavior.

Lets see from code perspective. Our beverage class:


package mynotes.designPatterns.structural;

public abstract class Beverage {

String description ="Unknown Beverage";

public String getDescription() {
return description;
}

public abstract double cost();
}

Lets have the concrete implementation of the above class in Espresso and HouseBlend:


package mynotes.designPatterns.structural;

public class Espresso extends Beverage {

public Espresso() {
description="Espresso";
}

@Override
public double cost() {
return 1.99;
}

}


package mynotes.designPatterns.structural;

public class HouseBlend extends Beverage {

public HouseBlend() {
description="House Blend";
}

@Override
public double cost() {
return .99;
}

}

Creating CondimentDecorator:


package mynotes.designPatterns.structural;

public abstract class CondimentDecorator extends Beverage {

public abstract String getDescription();
}

Concrete implementation of decorators – Whip, Mocha:


package mynotes.designPatterns.structural;

public class Mocha extends CondimentDecorator {

Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage=beverage;
}

@Override
public String getDescription() {
return beverage.getDescription()+", Mocha";
}

@Override
public double cost() {
return beverage.cost()+.20;
}

}


package mynotes.designPatterns.structural;
public class Whip extends CondimentDecorator {

Beverage beverage;
public Whip(Beverage beverage) {
this.beverage=beverage;
}

@Override
public String getDescription() {
return beverage.getDescription()+", Whip";
}

@Override
public double cost() {
return beverage.cost()+.10;
}

}

Let run using DecoratorApp:


package mynotes.designPatterns.structural;

public class DecoratorApp {

public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " =$" + beverage.cost());

Beverage beverage2 = new HouseBlend();
System.out.println(beverage2.getDescription() + " =$" + beverage2.cost());
beverage2 = new Mocha(beverage2);
System.out.println(beverage2.getDescription() + " =$" + beverage2.cost());
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " =$" + beverage2.cost());
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " =$" + beverage2.cost());

}
}

Output:


Espresso =$1.99
House Blend =$0.99
House Blend, Mocha =$1.19
House Blend, Mocha, Whip =$1.29
House Blend, Mocha, Whip, Whip =$1.3900000000000001

As you can see, with each addition/decorating the object the cost increases.

Note – We can use interface instead of abstract class also. Decorators are typically created by using other patterns like Factory and
Builder. Once we’ve covered these patterns, you’ll see that the creation of the concrete component with its decorator is “well encapsulated”.

When to use Decorator pattern in Java

  •  When sub classing is become impractical and we need large number of different possibilities to make independent object or we can say we have number of combination for an object.
  • Secondly when we want to add functionality to individual object not to all object at run-time we use decorator design pattern.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: