Decorator pattern is a structural design pattern that attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
So what exactly is that supposed to mean ??
Let us assume that our client is a travel company specializing in trips from the United States to Dubai. In addition to its core offering, the company provides optional extension packages, including :
- Mauritius
- Abu Dhabi
- Oman
- Qatar
- Bahrain
In order to implement this, the first thought that comes to mind is having an interface, that all travel packages will have to follow.
interface TravelPackage {
List<String> placesCovered();
double cost();
}Now that we have our base interface ready for action, let’s create our concrete classes implementing this interface.

So our base concrete classes would be like:
public class BaseDubaiPackage implements TravelPackage {
protected List<String> places = new ArrayList<>();
protected double baseCost = 1200.0;
public BaseDubaiPackage() {
places.add("Dubai");
}
@Override
public List<String> placesCovered() {
return places;
}
@Override
public double cost() {
return baseCost;
}
}
Now that we have implemented the base concrete class, let’s implement the optional concrete travel classes.
Note that there will be a concrete class for each of the trip packages.
public class MauritiusPackage extends BaseDubaiPackage {
public MauritiusPackage() {
super();
this.places.add("Mauritius");
this.baseCost += 850.0;
}
}
public class AbuDhabiPackage extends BaseDubaiPackage {
public AbuDhabiPackage() {
super();
this.places.add("Abu Dhabi");
this.baseCost += 120.0;
}
}
public class OmanPackage extends BaseDubaiPackage {
public OmanPackage() {
super();
this.places.add("Oman");
this.baseCost += 90.0;
}
}
public class QatarPackage extends BaseDubaiPackage {
public QatarPackage() {
super();
this.places.add("Qatar");
this.baseCost += 130.0;
}
}
public class BahrainPackage extends BaseDubaiPackage {
public BahrainPackage() {
super();
this.places.add("Bahrain");
this.baseCost += 95.0;
}
}
/* Similarly implement two-destination
and three-destination concrete classes */By now you would have realized that we have created a maintenance nightmare for ourselves 😱.
So what can we do ??
Decorator pattern to the rescue …
We saw that adding an explosion of classes didn’t work out well for us.
So here is what we are going to do.
We’ll start with the base class(here Dubai) and “decorate” it with required trip packages at runtime.
For example, if we want a Dubai → Mauritius → Abu Dhabi trip package, then we will:
i. Start with a Dubai trip Object.

ii. Decorate it with Mauritius Object.

iii. Decorate it with Abu Dhabi Object

So there are a few things we need to understand about a decorator:
- Decorators have the same supertype as the object they decorate.
- We can use one or more decorators to wrap an object.
- Since decorator has the same supertype as the object it decorates, we can pass around a decorated object in place of the original wrapped object.
- The decorator adds it’s own behavior before/after delegating to the object it decorates to do the rest of the job .
- Objects can be decorated anytime (even dynamically at runtime).
Let’s understand this with the help of a class diagram:

- The concrete component is the base object we will add behavior to. It extends the component.
- Each decorator HAS-A component, which means that the decorator has an instance variable that holds reference to a component.
- Decorators implement the same interface or abstract class they are going to decorate.
- The concrete decorator inherits from the decorator class, an instance variable for the thing it decorates(the component the decorator wraps).
- Decorators can add new methods.
So now, if we try to create a similar class diagram for our travel agency, we will end up with something like:

So as per the above class diagram, our TravelPackage interface remains the same:
public interface TravelPackage {
List<String> placesCovered();
double cost();
}Our concrete base package implements the travel package:
public class BaseDubaiPackage implements TravelPackage {
private final List<String> places = new ArrayList<>();
private final double baseCost = 1200.0;
public BaseDubaiPackage() {
places.add("Dubai");
}
@Override
public List<String> placesCovered() {
return new ArrayList<>(places);
}
@Override
public double cost() {
return baseCost;
}
}
Our abstract decorator will look something like:
public abstract class TravelPackageDecorator implements TravelPackage {
protected final TravelPackage travelPackage;
public TravelPackageDecorator(TravelPackage travelPackage) {
this.travelPackage = travelPackage;
}
@Override
public List<String> placesCovered() {
return travelPackage.placesCovered();
}
@Override
public double cost() {
return travelPackage.cost();
}
}
Now we can have the concrete extensions of our abstract decorator class:
public class MauritiusDecorator extends TravelPackageDecorator {
public MauritiusDecorator(TravelPackage travelPackage) {
super(travelPackage);
}
@Override
public List<String> placesCovered() {
List<String> places = super.placesCovered();
places.add("Mauritius");
return places;
}
@Override
public double cost() {
return super.cost() + 850.0;
}
}public class AbuDhabiDecorator extends TravelPackageDecorator {
public AbuDhabiDecorator(TravelPackage travelPackage) {
super(travelPackage);
}
@Override
public List<String> placesCovered() {
List<String> places = super.placesCovered();
places.add("Abu Dhabi");
return places;
}
@Override
public double cost() {
return super.cost() + 120.0;
}
}public class OmanDecorator extends TravelPackageDecorator {
public OmanDecorator(TravelPackage travelPackage) {
super(travelPackage);
}
@Override
public List<String> placesCovered() {
List<String> places = super.placesCovered();
places.add("Oman");
return places;
}
@Override
public double cost() {
return super.cost() + 90.0;
}
}and similarly we can also create the concrete decorators for Qatar and Bahrain.
Now we can easily use the marvel of decorator design pattern to plan our next travel.
public class PlanItinerary {
public static void main(String[] args) {
TravelPackage package = new BaseDubaiPackage();
package = new MauritiusDecorator(package);
package = new AbuDhabiDecorator(package);
package = new OmanDecorator(package);
System.out.println("Places Covered: " + package.placesCovered());
System.out.println("Total Cost: " + package.cost());
}
}Decorator Design Pattern is a great pattern for creating flexible designs and staying close to the open-close principle, but it can also have some disadvantages:
- A lot of small classes may get added to a design occasionally resulting in a design that is not very straightforward to understand.
- Introducing decorators can increase the complexity of code needed to instantiate the component. Once decorators are implemented, we not not only have to initialize the component, but also wrap it with a number of decorators.
So… given these disadvantages, when should you be using decorator design pattern ??
Decorator Design Pattern allows developers to modify object behavior dynamically at runtime, avoiding rigid, static class hierarchies. One should consider utilizing this pattern when these specific design challenges arise:
- The core strength of the Decorator pattern is its ability to attach additional functionality or responsibilities to an individual object at runtime. So, instead of hardcoding every potential behavior into a base class or subclass, decorators allow you to select and apply enhancements precisely when and where they are needed.
- If you have a primary class with several independent, optional features that can be combined in many permutations, traditional inheritance leads to unmanageable class hierarchies (often referred to as class explosion).
- The structure of the decorator pattern is inherently hierarchical and recursive. Hence, you can apply decorators one after another, layering features gradually in a controlled and traceable manner like wrapping layers around a gift🎁.
And with that, we’ve wrapped up the Decorator Design Pattern — you’re now fully equipped with everything you need to know on Decorators 🥳.
.