What is Decorator Design Pattern? Learn with Real-World Examples
1. What is a Design Pattern.
A design pattern is a proven, reusable solution to a commonly occurring software design problem. It represents best practices developed by experienced software developers to solve recurring problems in object‑oriented design.
2. What is Decorator Design Pattern .
Decorator Pattern allows behavior to be added to an object dynamically without modifying its existing code.
Decorator Design Pattern
- When we want to enhance the behaviour of our existing object dynamically as and when required then we can use decorator design pattern.
- Decorator wraps an object within itself and provides same interface as the wrapped object. So the client of original object does not need to change.
Implementation of Decorator:
- Component defines interface needed or already used by client
- Concrete component implements the component
- We define our decorator implements component & also needs reference to concrete components
In decorator methods we provide additional behaviour on top that provided by concrete component instance

3.Why Decorator Pattern is Needed
1. Avoids Too Many Subclasses
Instead of creating multiple subclasses, decorators allow you to combine features dynamically.
Example:
- BasicCoffee
- MilkDecorator
- SugarDecorator
- ChocolateDecorator
2. Adds Features at Runtime
You can wrap an object with additional behavior whenever required.
Coffee coffee = new SugarDecorator(
new MilkDecorator(
new BasicCoffee()));
3. Follows Open/Closed Principle
Decorator pattern keeps existing classes closed for modification but open for extension.
4. More Flexible Than Inheritance
Inheritance creates fixed behavior at compile time.
5. Improves Code Reusability
Each decorator can be reused across multiple objects.
4. Structure of decorator design pattern .
1) Component (Interface)
This defines the common interface for both concrete objects and decorators.
Responsibility:
- Declares common operations
- Acts as base type for wrapping objects
Example:
public interface Coffee {
String getDescription();
double getCost();
}
2) Concrete Component
This is the original object that will receive additional behavior.
Responsibility:
- Implements the component interface
- Provides basic/default functionality
Example:
public class BasicCoffee implements Coffee {
public String getDescription() {
return "Basic Coffee";
}
public double getCost() {
return 100;
}
}
3) Decorator (Decorator class)
This class implements the same interface as the component and contains a reference to the wrapped object.
Responsibility:
- Maintains reference of component object
- Delegates request to wrapped object
Example:
public class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
4) Concrete Decorators
These classes add extra responsibilities/behavior to the object.
Examples:
- MilkDecorator
- SugarDecorator
- ChocolateDecorator
Example:
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
public double getCost() {
return coffee.getCost() + 20;
}
}
- Rain Cloud Aroma Diffuser: Elevate your home with this electric aroma diffuser for home, featuring a stunning rain cloud design that blends modern sophistication with functionality.
Complete Example with explanation
1. Component Interface
The interface or abstract class defining the methods that will be implemented.
public interface Coffee {
String getDescription();
double getCost();
}
2. Component Implementation
The basic implementation of the component interface. We can have BasicCoffee class as our component implementation.
public class BasicCoffee implements Coffee {
public String getDescription() {
return "Basic Coffee";
}
public double getCost() {
return 100;
}
}
3.Decorator
Decorator class implements the component interface and it has a HAS-A relationship with the component interface. The component variable should be accessible to the child decorator classes .
public class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
4.Concrete Decorators
Extending the base decorator functionality and modifying the component behavior accordingly.
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
public double getCost() {
return coffee.getCost() + 20;
}
}
SigarDecorator.java
public class SigarDecorator extends CoffeeDecorator {
public SigarDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
public double getCost() {
return coffee.getCost() + 10;
}
}
ChocolateDecorator.java
public class ChocolateDecorator extends CoffeeDecorator {
public ChocolateDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
public double getCost() {
return coffee.getCost() + 10;
}
}
DecoratorClien.java
public class DecoratorClien{
public static void main(String[] args) {
// Basic coffee
Coffee coffee = new BasicCoffee();
System.out.println("Order 1: " + coffee.getDescription());
System.out.println("Cost: ₹" + coffee.getCost());
System.out.println("----------------------");
// Coffee with chocolate
Coffee chocolateCoffee = new ChocolateDecorator(new BasicCoffee());
System.out.println("Order 2: " + chocolateCoffee.getDescription());
System.out.println("Cost: ₹" + chocolateCoffee.getCost());
System.out.println("----------------------");
// Coffee with milk + chocolate
Coffee specialCoffee = new ChocolateDecorator(
new MilkDecorator(
new BasicCoffee()
)
);
System.out.println("Order 3: " + specialCoffee.getDescription());
System.out.println("Cost: ₹" + specialCoffee.getCost()); }
}
Explanation
- Since we have decorator and concrete classes extending from common component , avoid large state in this base class as decorators may not need all that state.
- Pay attention to equals and hashcode methods of decorator . when using decorators , you have to decide if decorated object is equal to same instance without decorator.
- Decorators are more flexible & powerful than inheritance . Inheritance is static by definition but decorators allow you to dynamically compose behaviour using object at runtime .