# Decorator Design Pattern in Java: Explained with a Simple Coffee Example

The Decorator Design Pattern is one of the most useful structural design patterns in software development.

It allows us to add new features or responsibilities to an existing object without modifying its original class.

In simple words:

> The Decorator Pattern adds extra functionality to an object by wrapping it inside another object.

Let us understand this pattern using a simple coffee shop example.

* * *

## 1\. Real-Life Example

Imagine that you visit a coffee shop and order a plain coffee.

The plain coffee costs ₹50.

You may also add optional items such as:

*   Milk
    
*   Sugar
    
*   Cream
    
*   Chocolate
    
*   Caramel
    

Your final order may look like this:

```text
Plain Coffee
Plain Coffee + Milk
Plain Coffee + Milk + Sugar
Plain Coffee + Milk + Sugar + Cream
```

The basic coffee remains the same. We are only adding extra features to it.

Each extra item decorates the original coffee.

This is the main idea behind the Decorator Design Pattern.

* * *

## 2\. The Problem Without the Decorator Pattern

Suppose we create a separate class for every possible coffee combination.

```java
class PlainCoffee {
}

class MilkCoffee {
}

class SugarCoffee {
}

class MilkSugarCoffee {
}

class MilkSugarCreamCoffee {
}
```

This approach may work when there are only two or three combinations.

However, imagine that the coffee shop supports the following toppings:

```text
Milk
Sugar
Cream
Chocolate
Caramel
Honey
Vanilla
```

The number of possible combinations will increase rapidly.

We may need classes such as:

```text
MilkCoffee
SugarCoffee
CreamCoffee
MilkSugarCoffee
MilkCreamCoffee
SugarCreamCoffee
MilkSugarCreamCoffee
ChocolateMilkCoffee
CaramelSugarCoffee
```

This creates too many classes.

This problem is known as **class explosion**.

The Decorator Pattern solves this problem by allowing us to combine small reusable decorators at runtime.

* * *

## 3\. Definition of the Decorator Pattern

The Decorator Pattern is a structural design pattern that dynamically adds new responsibilities to an object by wrapping it inside another object that follows the same interface.

A simpler definition is:

> The Decorator Pattern adds new behaviour to an object without changing the original class.

Instead of creating multiple subclasses, we create small wrapper classes that add one responsibility at a time.

* * *

## 4\. Main Components of the Decorator Pattern

The Decorator Pattern generally contains four main components:

1.  Component interface
    
2.  Concrete component
    
3.  Base decorator
    
4.  Concrete decorators
    

In our coffee example:

| Pattern Component | Coffee Example |
| --- | --- |
| Component | `Coffee` |
| Concrete Component | `PlainCoffee` |
| Base Decorator | `CoffeeDecorator` |
| Concrete Decorators | `MilkDecorator`, `SugarDecorator`, `CreamDecorator` |

Let us implement each component step by step.

* * *

# 5\. Step 1: Create the Component Interface

The component interface defines the common operations that will be supported by both the original object and its decorators.

```java
interface Coffee {

    String getDescription();

    int getCost();
}
```

Every type of coffee must provide:

```java
getDescription();
getCost();
```

The important point is that both the original coffee and all decorators will implement the same `Coffee` interface.

* * *

# 6\. Step 2: Create the Concrete Component

The concrete component is the original object that we want to decorate.

```java
class PlainCoffee implements Coffee {

    @Override
    public String getDescription() {
        return "Plain Coffee";
    }

    @Override
    public int getCost() {
        return 50;
    }
}
```

Here:

```text
Plain Coffee cost = ₹50
```

`PlainCoffee` is the basic object.

Milk, sugar, cream, and other features will be added around this object.

* * *

# 7\. Step 3: Create the Base Decorator

The base decorator implements the same `Coffee` interface and stores a reference to another `Coffee` object.

```java
abstract class CoffeeDecorator implements Coffee {

    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}
```

The most important line is:

```java
protected Coffee coffee;
```

This means that a decorator contains another `Coffee` object.

For example:

```java
new MilkDecorator(new PlainCoffee());
```

Here, `MilkDecorator` wraps the `PlainCoffee` object.

This wrapping mechanism is the heart of the Decorator Pattern.

* * *

# 8\. Step 4: Create the Milk Decorator

The milk decorator adds milk to an existing coffee.

```java
class MilkDecorator extends CoffeeDecorator {

    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + Milk";
    }

    @Override
    public int getCost() {
        return coffee.getCost() + 20;
    }
}
```

Milk costs ₹20.

The decorator first asks the wrapped coffee for its current cost:

```java
coffee.getCost();
```

It then adds the milk cost:

```java
coffee.getCost() + 20;
```

Similarly, it adds `" + Milk"` to the description.

* * *

# 9\. Create the Sugar Decorator

```java
class SugarDecorator extends CoffeeDecorator {

    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + Sugar";
    }

    @Override
    public int getCost() {
        return coffee.getCost() + 10;
    }
}
```

Sugar costs ₹10.

The decorator adds ₹10 to the cost of the wrapped coffee.

* * *

# 10\. Create the Cream Decorator

```java
class CreamDecorator extends CoffeeDecorator {

    public CreamDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + Cream";
    }

    @Override
    public int getCost() {
        return coffee.getCost() + 30;
    }
}
```

Cream costs ₹30.

It adds cream to the description and ₹30 to the existing cost.

* * *

# 11\. Complete Java Program

```java
interface Coffee {

    String getDescription();

    int getCost();
}

class PlainCoffee implements Coffee {

    @Override
    public String getDescription() {
        return "Plain Coffee";
    }

    @Override
    public int getCost() {
        return 50;
    }
}

abstract class CoffeeDecorator implements Coffee {

    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

class MilkDecorator extends CoffeeDecorator {

    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + Milk";
    }

    @Override
    public int getCost() {
        return coffee.getCost() + 20;
    }
}

class SugarDecorator extends CoffeeDecorator {

    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + Sugar";
    }

    @Override
    public int getCost() {
        return coffee.getCost() + 10;
    }
}

class CreamDecorator extends CoffeeDecorator {

    public CreamDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + Cream";
    }

    @Override
    public int getCost() {
        return coffee.getCost() + 30;
    }
}

public class Main {

    public static void main(String[] args) {

        Coffee coffee = new PlainCoffee();

        System.out.println(coffee.getDescription());
        System.out.println("Cost: Rs. " + coffee.getCost());

        coffee = new MilkDecorator(coffee);
        coffee = new SugarDecorator(coffee);
        coffee = new CreamDecorator(coffee);

        System.out.println();
        System.out.println(coffee.getDescription());
        System.out.println("Cost: Rs. " + coffee.getCost());
    }
}
```

Output:

```text
Plain Coffee
Cost: Rs. 50

Plain Coffee + Milk + Sugar + Cream
Cost: Rs. 110
```

The final cost is calculated as:

```text
Plain Coffee = ₹50
Milk         = ₹20
Sugar        = ₹10
Cream        = ₹30
-------------------
Total        = ₹110
```

* * *

# 12\. How Does Object Wrapping Work?

Consider the following code:

```java
Coffee coffee = new PlainCoffee();

coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
coffee = new CreamDecorator(coffee);
```

After the first line:

```text
coffee → PlainCoffee
```

After adding milk:

```text
coffee → MilkDecorator → PlainCoffee
```

After adding sugar:

```text
coffee → SugarDecorator → MilkDecorator → PlainCoffee
```

After adding cream:

```text
coffee → CreamDecorator → SugarDecorator → MilkDecorator → PlainCoffee
```

The same object structure can also be created in one statement:

```java
Coffee coffee =
        new CreamDecorator(
            new SugarDecorator(
                new MilkDecorator(
                    new PlainCoffee()
                )
            )
        );
```

The outermost object is `CreamDecorator`.

Inside it, there is a `SugarDecorator`.

Inside the sugar decorator, there is a `MilkDecorator`.

Inside the milk decorator, there is a `PlainCoffee`.

* * *

# 13\. Understanding the `getCost()` Call Flow

When we execute:

```java
coffee.getCost();
```

The call starts from the outermost decorator.

```text
CreamDecorator.getCost()
        ↓
SugarDecorator.getCost()
        ↓
MilkDecorator.getCost()
        ↓
PlainCoffee.getCost()
```

Now the values return in the opposite direction.

### Plain coffee

```text
PlainCoffee returns 50
```

### Milk decorator

```text
50 + 20 = 70
```

### Sugar decorator

```text
70 + 10 = 80
```

### Cream decorator

```text
80 + 30 = 110
```

Therefore, the final result is:

```text
₹110
```

We can represent the calculation as:

```text
CreamDecorator.getCost()

= SugarDecorator.getCost() + 30

= MilkDecorator.getCost() + 10 + 30

= PlainCoffee.getCost() + 20 + 10 + 30

= 50 + 20 + 10 + 30

= 110
```

This recursive delegation is the central working mechanism of the Decorator Pattern.

* * *

* * *

# 15\. Important Relationships in the Decorator Pattern

Consider the following class:

```java
abstract class CoffeeDecorator implements Coffee {

    protected Coffee coffee;
}
```

This class has two important relationships with `Coffee`.

## IS-A Relationship

```java
CoffeeDecorator implements Coffee
```

Therefore:

```text
CoffeeDecorator IS-A Coffee
```

A decorator can be used wherever a `Coffee` object is expected.

For example:

```java
Coffee coffee = new MilkDecorator(new PlainCoffee());
```

## HAS-A Relationship

```java
protected Coffee coffee;
```

Therefore:

```text
CoffeeDecorator HAS-A Coffee
```

The decorator stores and wraps another coffee object.

This is why we often describe the Decorator Pattern using the following statement:

> A decorator is a component and also contains a component.

In this example:

```text
CoffeeDecorator IS-A Coffee
CoffeeDecorator HAS-A Coffee
```

* * *

# 16\. Why Does the Decorator Implement the Same Interface?

The decorator implements the `Coffee` interface so that it can replace the original object.

Both of the following objects are treated as `Coffee`:

```java
Coffee coffee1 = new PlainCoffee();

Coffee coffee2 =
        new MilkDecorator(
            new PlainCoffee()
        );
```

Because every decorator is also a `Coffee`, decorators can be nested inside one another.

```java
Coffee coffee =
        new SugarDecorator(
            new MilkDecorator(
                new PlainCoffee()
            )
        );
```

Without the common interface, this chaining would not be possible.

* * *

# 17\. Why Not Use Inheritance?

We could try to solve the problem using inheritance.

```java
class Coffee {
}

class MilkCoffee extends Coffee {
}

class SugarCoffee extends Coffee {
}

class MilkSugarCoffee extends Coffee {
}

class MilkSugarCreamCoffee extends Coffee {
}
```

However, this creates a separate class for every combination.

As the number of optional features grows, the number of subclasses also grows.

The Decorator Pattern uses composition instead.

```java
new MilkDecorator(
    new PlainCoffee()
);
```

Or:

```java
new SugarDecorator(
    new MilkDecorator(
        new PlainCoffee()
    )
);
```

With decorators, existing features can be combined in different ways without creating new classes for every combination.

The main difference is:

```text
Inheritance adds behaviour through subclasses.

Decorator adds behaviour through object composition.
```

Inheritance usually defines behaviour at compile time.

Decorator allows behaviour to be added dynamically at runtime.

* * *

# 18\. Benefits of the Decorator Pattern

## Dynamic Behaviour

Features can be added while the program is running.

```java
Coffee coffee = new PlainCoffee();

coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
```

The final combination can depend on the user's choices.

## No Modification of the Original Class

`PlainCoffee` does not need to know anything about milk, sugar, or cream.

New features are added through separate decorators.

## Avoids Class Explosion

We do not need a separate class for every possible combination.

The same decorators can be reused and combined.

## Supports the Open/Closed Principle

The Open/Closed Principle states:

> Software entities should be open for extension but closed for modification.

We can add a new decorator without changing the existing classes.

```java
class ChocolateDecorator extends CoffeeDecorator {

    public ChocolateDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + Chocolate";
    }

    @Override
    public int getCost() {
        return coffee.getCost() + 25;
    }
}
```

No changes are required in:

```text
PlainCoffee
MilkDecorator
SugarDecorator
CreamDecorator
```

## Supports the Single Responsibility Principle

Each decorator has one responsibility.

```text
MilkDecorator  → Adds milk
SugarDecorator → Adds sugar
CreamDecorator → Adds cream
```

This makes the code easier to understand and maintain.

## Follows Composition Over Inheritance

Instead of creating complex inheritance hierarchies, the Decorator Pattern combines objects.

* * *

# 19\. Disadvantages of the Decorator Pattern

The Decorator Pattern is useful, but it also has some disadvantages.

## Many Small Objects

A decorated object may contain several wrapper objects.

```text
CreamDecorator
SugarDecorator
MilkDecorator
PlainCoffee
```

This can create many small objects.

## Debugging Can Become Difficult

Deeply nested decorators can make the call flow harder to understand.

```java
new A(
    new B(
        new C(
            new D(object)
        )
    )
);
```

## Decorator Order May Matter

In some systems, changing the order of decorators may change the result.

For example:

```java
new CompressionDecorator(
    new EncryptionDecorator(data)
);
```

This means:

```text
Encrypt first, then compress.
```

But:

```java
new EncryptionDecorator(
    new CompressionDecorator(data)
);
```

This means:

```text
Compress first, then encrypt.
```

These two operations may produce different results.

## Object Creation Can Look Complex

A deeply decorated object may be difficult to read when created in one statement.

Using step-by-step wrapping can improve readability.

```java
Coffee coffee = new PlainCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
coffee = new CreamDecorator(coffee);
```

* * *

# 20\. When Should We Use the Decorator Pattern?

Use the Decorator Pattern when:

*   Features need to be added dynamically.
    
*   Many optional combinations are possible.
    
*   The original class should not be modified.
    
*   Inheritance is creating too many subclasses.
    
*   Features should be reusable and independent.
    
*   Responsibilities need to be added one at a time.
    
*   Different users may select different combinations of features.
    

Common examples include:

```text
Coffee and pizza toppings
Notification channels
File compression
File encryption
Logging
Authentication
Authorization
Web middleware
Java InputStream classes
Graphical user-interface components
```

* * *

# 21\. Real Java Example: InputStream

Java's I/O library is one of the most popular real-world examples of the Decorator Pattern.

```java
InputStream inputStream =
        new BufferedInputStream(
            new FileInputStream("data.txt")
        );
```

Here:

```text
FileInputStream reads data from the file.

BufferedInputStream adds buffering behaviour.
```

More decorators can be added:

```java
DataInputStream inputStream =
        new DataInputStream(
            new BufferedInputStream(
                new FileInputStream("data.txt")
            )
        );
```

The wrapping structure is:

```text
DataInputStream
    └── BufferedInputStream
            └── FileInputStream
```

Each wrapper adds new functionality while still behaving like an input stream.

* * *

# 22\. Another Example: Notification System

Suppose a basic notification system sends an email.

We may want to add:

*   SMS notification
    
*   WhatsApp notification
    
*   Slack notification
    
*   Push notification
    

The wrapping structure may look like this:

```text
SlackNotificationDecorator
    └── WhatsAppNotificationDecorator
            └── SMSNotificationDecorator
                    └── EmailNotification
```

When the notification method is called, every decorator performs its responsibility.

This allows one notification to be sent through multiple channels without creating classes such as:

```text
EmailAndSMSNotification
EmailAndWhatsAppNotification
EmailSMSAndSlackNotification
```

* * *

# 23\. Decorator Pattern vs Strategy Pattern

Both patterns use composition, but their purposes are different.

## Strategy Pattern

The Strategy Pattern selects one behaviour from multiple available behaviours.

For example:

```text
UPI Payment
Credit Card Payment
Cash on Delivery
```

Usually, one strategy is selected at a time.

```java
paymentService.setPaymentStrategy(
    new UpiPayment()
);
```

## Decorator Pattern

The Decorator Pattern adds multiple responsibilities around an existing object.

```text
Coffee + Milk + Sugar + Cream
```

Multiple decorators can be chained together.

The simplest difference is:

```text
Strategy selects or replaces behaviour.

Decorator adds behaviour.
```

* * *

# 24\. Decorator Pattern vs Proxy Pattern

Decorator and Proxy may appear similar because both wrap another object.

However, their intentions are different.

## Decorator

A decorator adds new functionality.

Example:

```text
Plain Coffee + Milk
```

## Proxy

A proxy controls access to an object.

It may provide:

*   Permission checking
    
*   Lazy loading
    
*   Caching
    
*   Remote communication
    
*   Logging
    
*   Security
    

The simplest difference is:

```text
Decorator enhances behaviour.

Proxy controls access.
```

* * *

# 25\. Decorator Pattern vs Adapter Pattern

The Adapter Pattern changes an object's interface so that it becomes compatible with another system.

The Decorator Pattern keeps the same interface and adds new behaviour.

```text
Adapter changes the interface.

Decorator keeps the interface but adds behaviour.
```

* * *

# 26\. Interview Definition

A good interview definition is:

> The Decorator Pattern is a structural design pattern that dynamically adds new responsibilities to an object by wrapping it inside another object that implements the same interface. It provides a flexible alternative to subclassing.

A simpler interview answer is:

> The Decorator Pattern adds extra behaviour to an object at runtime without modifying its original class.

* * *

# 27\. How to Explain the Code in an Interview

You can explain the coffee example like this:

> `Coffee` is the common component interface. `PlainCoffee` is the concrete component that provides the basic behaviour. `CoffeeDecorator` is an abstract decorator that implements the same interface and stores a reference to another `Coffee` object. `MilkDecorator`, `SugarDecorator`, and `CreamDecorator` are concrete decorators. Each decorator delegates the operation to the wrapped object and adds its own additional behaviour. This allows us to create different coffee combinations dynamically without creating a separate subclass for every combination.

* * *

# 28\. Common Interview Questions

## Which category does the Decorator Pattern belong to?

The Decorator Pattern is a:

```text
Structural Design Pattern
```

## What is the main purpose of the Decorator Pattern?

Its purpose is to add new responsibilities to an object dynamically without changing its original class.

## Why does a decorator implement the same interface?

It implements the same interface so that:

*   It can replace the original object.
    
*   It can wrap other decorators.
    
*   Multiple decorators can be chained.
    
*   The client does not need to know whether it is using a basic object or a decorated object.
    

## What relationships are present in a decorator?

A decorator has both:

```text
IS-A component
HAS-A component
```

## Which SOLID principles does it support?

It mainly supports:

```text
Open/Closed Principle
Single Responsibility Principle
```

## What principle is commonly associated with the Decorator Pattern?

```text
Composition over inheritance
```

## Can decorators be added at runtime?

Yes. Decorators can be added dynamically based on user choices or program conditions.

## What is the main disadvantage of the pattern?

It may create many small wrapper objects and make the call flow difficult to debug.

* * *

# 29\. The Heart of the Decorator Pattern

The most important part of the pattern is this type of method:

```java
@Override
public int getCost() {
    return coffee.getCost() + 20;
}
```

The decorator:

1.  Calls the wrapped object's method.
    
2.  Receives the existing result.
    
3.  Adds its own behaviour.
    
4.  Returns the updated result.
    

The general formula is:

```text
Decorator Result
=
Wrapped Object Result
+
Additional Behaviour
```

In the coffee example:

```text
Milk Decorator Cost
=
Existing Coffee Cost
+
Milk Cost
```

* * *

# 30\. Final Summary

The Decorator Design Pattern allows us to add extra responsibilities to an object by wrapping it inside another object.

The original class remains unchanged.

Each decorator:

*   Implements the same interface.
    
*   Stores a reference to another object of that interface.
    
*   Delegates work to the wrapped object.
    
*   Adds its own additional behaviour.
    

The wrapping structure may look like this:

```text
CreamDecorator
    └── SugarDecorator
            └── MilkDecorator
                    └── PlainCoffee
```

The key idea can be summarized in one sentence:

> Wrap an object inside another object that follows the same interface, call the wrapped object's method, and add extra behaviour before or after that call.

The Decorator Pattern is especially useful when a system has many optional features and those features need to be combined dynamically without creating a large number of subclasses.
