Decorator Design Pattern in Java
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;
}@Override
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 class Strawberry implements IceCream {@Override
public int getCost() {
return 15;
}@Override
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();
}@Override
public String getDecription() {
return this.object.getDecription();
}}
Step 4:
public class Cashewnuts extends Additions {public Cashewnuts(IceCream object) {
super(object);
}
@Override
public int getCost() {
return this.object.getCost()+ 10;
}
@Override
public String getDecription() {
return this.object.getDecription()
+ ” with cashewnuts topping”;
}}public class Peanuts extends Additions {public Peanuts(IceCream object) {
super(object);
}
@Override
public int getCost() {
return this.object.getCost()+ 5;
}
@Override
public String getDecription() {
return this.object.getDecription()
+ ” with peanuts topping”;
}}
Step 5:
public class Test {/**
* @param args
*/
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());}}
Verify the output
10Vanilla ice cream20Vanilla ice cream with cashewnuts topping25Vanilla 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.