Decorator Design Pattern in Java
By: Prabhu Kumar
Tags: Decorators, Uml, Code, Java, Design Patterns

The Decorator Design Pattern assigns responsibilities to an object dynamically and it provides a flexible alternative to subclassing for extending functionality.

Structure Summary

Ensure the context is a single core (or non-optional) component, several optional embellishments or wrappers, and an interface that is common to all

Create a component interface that makes all classes interchangeable

Define Core Component class and Decorator base class that inherit from the component interface

Define a Decorator derived class for each optional embellishment

Decorator derived classes implement their wrapper functionality and delegate to the Decorator base class

The client configures the type and ordering of Core and Decorator objects

The participant classes in the decorator pattern are

Component

Interface for objects that can have responsibilities added to them dynamically

Concrete Component

Defines an object to which additional responsibilities can be added

Decorator

Maintains a reference to a Component object and defines an interface that conforms to Component’s interface

Concrete Decorators

Concrete Decorators extend the functionality of the component by adding state or adding behavior

UML Diagram

Implementation steps

Step 1 — Create a component interface

Step 2 — Create concrete component classes implementing the component interface

Step 3 — Create abstract decorator class implementing the component interface

Step 4 — Create concrete decorator classes extending the abstract decorator class

Step 5 — Use the concrete decorator classes to decorate component objects

Code Example

Step 1:

public interface IceCream { public int getCost(); public String getDecription(); }

Step 2:

public class Vanilla implements IceCream { @Override

public int getCost() {

return 10;

} public int getCost() {return 10; @Override

public String getDecription() {

return “Vanilla ice cream”;

} public String getDecription() {return “Vanilla ice cream”; } public class PineApple implements IceCream { @Override

public int getCost() {

return 20;

}





@Override

public String getDecription() {

return “Pine Apple ice cream”;

} public int getCost() {return 20;public String getDecription() {return “Pine Apple ice cream”; } public class Strawberry implements IceCream { @Override

public int getCost() {

return 15;

} public int getCost() {return 15; @Override

public String getDecription() {

return “Straw berry ice cream”;

} public String getDecription() {return “Straw berry ice cream”; }

Step 3:

public class Additions implements IceCream {



IceCream object; public Additions(IceCream object) {

super();

this.object = object;

} @Override

public int getCost() {

return this.object. getCost();

} public int getCost() {return this.object. getCost(); @Override

public String getDecription() {

return this.object.getDecription();

} public String getDecription() {return this.object.getDecription(); }

Step 4:

public class Cashewnuts extends Additions {

super(object);



}



@Override

public int getCost() {

return this.object.getCost()+ 10;

}



@Override

public String getDecription() {

return this.object.getDecription()

+ ” with cashewnuts topping”;

} public Cashewnuts(IceCream object) {super(object);public int getCost() {return this.object.getCost()+ 10;public String getDecription() {return this.object.getDecription()+ ” with cashewnuts topping”; } public class Peanuts extends Additions {

super(object);

}



@Override

public int getCost() {

return this.object.getCost()+ 5;

}



@Override

public String getDecription() {

return this.object.getDecription()

+ ” with peanuts topping”;

} public Peanuts(IceCream object) {super(object);public int getCost() {return this.object.getCost()+ 5;public String getDecription() {return this.object.getDecription()+ ” with peanuts topping”; }

Step 5:

public class Test {

*

*/

public static void main(String[] args) {

IceCream vanilla = new Vanilla();

//cost of vanilla is 10

Additions cashews = new Cashewnuts(vanilla);

//cost of cashew nuts is 10

System.out.println(vanilla.getCost());

System.out.println(vanilla.getDecription());

System.out.println(cashews.getCost());

System.out.println(cashews.getDecription());

Additions peanuts = new Peanuts(cashews);

//cost of peanuts is 5

System.out.println(peanuts.getCost());

System.out.println(peanuts.getDecription()); /** @param args*/public static void main(String[] args) {IceCream vanilla = new Vanilla();//cost of vanilla is 10Additions cashews = new Cashewnuts(vanilla);//cost of cashew nuts is 10System.out.println(vanilla.getCost());System.out.println(vanilla.getDecription());System.out.println(cashews.getCost());System.out.println(cashews.getDecription());Additions peanuts = new Peanuts(cashews);//cost of peanuts is 5System.out.println(peanuts.getCost());System.out.println(peanuts.getDecription()); } }

Verify the output

10 Vanilla ice cream 20 Vanilla ice cream with cashewnuts topping 25 Vanilla ice cream with cashewnuts topping with peanuts topping

Summary

The Decorator Design Pattern is a structural design pattern

Use the Decorator pattern when you need to be able to assign extra behaviors to objects at runtime without breaking the code that uses these objects

I hope this explanation and Decorator Design Pattern code example have been helpful. If you like this tutorial please give a clap.