DEV Community

Cover image for Decorator Design Pattern in Java – Complete Guide
ZeeshanAli-0704
ZeeshanAli-0704

Posted on • Edited on

Decorator Design Pattern in Java – Complete Guide

πŸ• Decorator Design Pattern in Java β€” Explained with Pizza & Toppings

Writing clean, extensible, and maintainable object-oriented code is a challenge many developers face. One elegant solution for adding new behaviors without modifying existing code is the Decorator Design Pattern.

In this blog, we'll dive deep into the Decorator pattern using one of the most delicious real-world analogies: Pizza and Toppings!


πŸ“˜ Table of Contents


🧠 What is the Decorator Pattern?

The Decorator Design Pattern is a structural design pattern that lets you dynamically attach new behaviors or responsibilities to an object at runtime without altering its structure.

This is achieved by wrapping the original object inside a new object (called a decorator) that adds the new behavior.

βœ… It follows the Open/Closed Principle β€” you can extend functionality without modifying existing code.


🍴 Real World Analogy

Imagine you run a pizza shop.

You sell a base pizza, and customers can choose to add toppings like:

  • Extra cheese
  • Olives
  • Mushrooms
  • JalapeΓ±os

Creating a separate class for each topping combination like PizzaWithCheeseAndOlives would be chaotic. Instead, what if you could dynamically wrap a pizza with different toppings?

That’s exactly what the Decorator Pattern allows you to do.


🚨 Problem Statement

Without decorators, you might end up with many subclasses like:

class PizzaWithCheese {}
class PizzaWithCheeseAndOlives {}
class PizzaWithMushroomsAndCheeseAndOlives {}
// ... and so on
Enter fullscreen mode Exit fullscreen mode

This quickly becomes unmanageable as combinations grow.


🧱 Decorator Pattern Structure

Role Responsibility Example
Component Interface or abstract class Pizza
ConcreteComponent Real object implementing Component MargheritaPizza
Decorator Abstract class implementing Component PizzaDecorator
ConcreteDecorator Adds additional behavior CheeseTopping, OliveTopping

β˜• Java Implementation (Pizza Example)

1️⃣ Component Interface

public interface Pizza {
    String getDescription();
    double getCost();
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ Concrete Component

public class MargheritaPizza implements Pizza {
    @Override
    public String getDescription() {
        return "Margherita Pizza";
    }

    @Override
    public double getCost() {
        return 200.0;
    }
}
Enter fullscreen mode Exit fullscreen mode

3️⃣ Abstract Decorator

public abstract class PizzaDecorator implements Pizza {
    protected Pizza pizza;

    public PizzaDecorator(Pizza pizza) {
        this.pizza = pizza;
    }

    public String getDescription() {
        return pizza.getDescription();
    }

    public double getCost() {
        return pizza.getCost();
    }
}
Enter fullscreen mode Exit fullscreen mode

4️⃣ Concrete Decorators

public class CheeseTopping extends PizzaDecorator {
    public CheeseTopping(Pizza pizza) {
        super(pizza);
    }

    public String getDescription() {
        return pizza.getDescription() + ", Extra Cheese";
    }

    public double getCost() {
        return pizza.getCost() + 50.0;
    }
}
Enter fullscreen mode Exit fullscreen mode
public class OliveTopping extends PizzaDecorator {
    public OliveTopping(Pizza pizza) {
        super(pizza);
    }

    public String getDescription() {
        return pizza.getDescription() + ", Olives";
    }

    public double getCost() {
        return pizza.getCost() + 30.0;
    }
}
Enter fullscreen mode Exit fullscreen mode

5️⃣ Client Code

public class PizzaShop {
    public static void main(String[] args) {
        Pizza pizza = new MargheritaPizza();
        System.out.println(pizza.getDescription() + " => β‚Ή" + pizza.getCost());

        pizza = new CheeseTopping(pizza);
        pizza = new OliveTopping(pizza);

        System.out.println(pizza.getDescription() + " => β‚Ή" + pizza.getCost());
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

Margherita Pizza => β‚Ή200.0
Margherita Pizza, Extra Cheese, Olives => β‚Ή280.0
Enter fullscreen mode Exit fullscreen mode

πŸ” How the Decorator Pattern Works (Step by Step)

Pizza pizza = new OliveTopping(
                  new CheeseTopping(
                      new MargheritaPizza()));
Enter fullscreen mode Exit fullscreen mode

Call Flow for getDescription():

  • OliveTopping.getDescription() β†’ calls

    • CheeseTopping.getDescription() β†’ calls
    • MargheritaPizza.getDescription() β†’ "Margherita Pizza"
    • adds ", Extra Cheese"
  • adds ", Olives"

Final: "Margherita Pizza, Extra Cheese, Olives"

Call Flow for getCost():

  • Base Pizza = 200.0
  • Cheese = +50.0
  • Olives = +30.0
  • Final = β‚Ή280.0

βœ… The decorators wrap and extend the behavior dynamically.


βœ… Advantages

  • Open/Closed Principle: Add behavior without modifying existing code
  • Flexible: Combine decorators in any order
  • Avoids subclass explosion
  • Runtime customization: Change behavior during execution

❌ Disadvantages

  • Many small classes for each decorator
  • Debugging becomes harder with deep nesting
  • Order of decorators matters

πŸ›  When to Use It

Use the Decorator Pattern when:

  • You need to add optional features or behaviors
  • You want to avoid large class hierarchies
  • You need dynamic behavior composition at runtime

πŸ§ͺ Real World Examples in Java API

  • java.io.InputStream, OutputStream, BufferedReader, etc.
  • java.util.Collections.unmodifiableList() β€” wraps a list to prevent mutation

🧁 Conclusion

The Decorator Design Pattern is a flexible and powerful tool that helps you extend behavior without changing existing code. By using composition over inheritance, you keep your code modular, extensible, and maintainable.

Key Takeaway:

Decorators are like toppings on a pizza β€” each one adds flavor (behavior) while wrapping the same base pizza!


More Details:

Get all articles related to system design
Hastag: SystemDesignWithZeeshanAli

systemdesignwithzeeshanali

Git: https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli


πŸ“š Explore More Design Patterns in Java

* πŸ”Œ Strategy Design Pattern in Java – A Complete Guide

Top comments (0)