Software Design Pattern: Decorator Pattern
The decorator pattern is a structural pattern that provides a wrapper to the existing class. It allows us to dynamically add functionality and behavior to an object without affecting the behavior of other existing objects within the same class. We use inheritance to extend the behavior of the class. This takes place at compile-time, and all the instances of that class get the extended behavior.
Example:
A pizza is an actual illustration of a decorator design motif. Here, the basis of the pizza would be the original class, and the assortment of toppings would serve as the additional functionality. The pizza foundation (original class) will not be altered by the addition of any toppings (functionalities) by the consumer.
Another illustration would be to dress a human body. The functions of clothing are additions to the original class of the human body. Although you can choose to wear various types of clothing, the human body (original class) will not change.
Code:
public interface ChristmasTree {
String decorate();
}
public class ChristmasTreeImpl implements ChristmasTree {
@Override
public String decorate() {
return "Christmas tree";
}
}
public abstract class TreeDecorator implements ChristmasTree {
private final ChristmasTree tree;
public TreeDecorator(ChristmasTree tree) {
this.tree = tree;
}
@Override
public String decorate() {
return tree.decorate();
}
}
public class BubbleLights extends TreeDecorator {
public BubbleLights(ChristmasTree tree) {
super(tree);
}
@Override
public String decorate() {
return super.decorate() + decorateWithBubbleLights();
}
private String decorateWithBubbleLights() {
return " with Bubble Lights";
}
}
public class Tinsel extends TreeDecorator {
public Tinsel(ChristmasTree tree) {
super(tree);
}
@Override
public String decorate() {
return super.decorate() + decorateWithTinsel();
}
private String decorateWithTinsel() {
return " with Tinsel";
}
}
public static void main(String[] args) {
ChristmasTree tree1 = new BubbleLights(new Tinsel(new ChristmasTreeImpl()));
System.out.println(tree1.decorate());
}
Output:
Christmas tree with Tinsel with Bubble Lights
Explain:
The ChristmasTree interface defines the method decorate(), which returns a string. The ChristmasTreeImpl class implements this interface and returns the string “Christmas tree”.
The TreeDecorator abstract class implements the ChristmasTree interface and has a constructor that takes a ChristmasTree object. It also has an implementation of the decorate() method that simply calls the same method on the wrapped object.
The BubbleLights and Tinsel classes both extend the TreeDecorator class and add their own decorations to the tree. They both have constructors that take a ChristmasTree object and call the constructor of their superclass with that object. They also override the decorate() method to add their own decorations to the string returned by the wrapped object.
Finally, in the main method, we create a new ChristmasTreeImpl object and wrap it in a Tinsel object and then a BubbleLights object. When we call the decorate() method on this object, it will return “Christmas tree with Tinsel with Bubble Lights”.
Subscribe to my newsletter
Read articles from Jack Pritom Soren directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Jack Pritom Soren
Jack Pritom Soren
Software Engineer (SWE) specializing in Frontend development, proficient in JavaScript, React, Next.js, Angular, and a variety of frontend tools. Also skilled in MERN Stack. Committed to crafting clean, efficient code and driving innovation in every project. Passionate about collaborating with dynamic teams to create impactful solutions and continuously advance in the field of frontend development.