Skip to main content

Command Palette

Search for a command to run...

Decorator Design Pattern

Updated
•4 min read•View as Markdown
Decorator Design Pattern
S

Campus Maven at RiseIn Postman Student Expert Web Developer and Blockchain enthusiast

Why Decorator Pattern Exists

In real applications, we often need to add extra functionality to an object.

Examples:

  • Adding logging to a service

  • Adding authentication to a controller

  • Adding compression to a stream

  • Adding encryption to data

  • Adding extra toppings to a food order

The naive way:

Modify the original class.

Problem?

  • Violates Open/Closed Principle

  • Creates subclass explosion

  • Hard to maintain

Decorator Pattern solves this cleanly.


What is Decorator Pattern?

Decorator Pattern allows:

Adding new behavior to an object dynamically without modifying its structure.

In simple terms:

Instead of modifying the original class,
you wrap it inside another class that adds extra behavior.


Real Backend Scenario

Imagine you have a simple NotificationService.

You now want to:

  • Add logging

  • Add encryption

  • Add performance tracking

Instead of modifying the core service,
you wrap it with decorators.


Clean Java Implementation

Step 1 — Component Interface

public interface NotificationService {
    void send(String message);
}

Step 2 — Concrete Component

public class BasicNotificationService implements NotificationService {

    @Override
    public void send(String message) {
        System.out.println("Sending notification: " + message);
    }
}

This is core functionality.


Step 3 — Base Decorator Class

public abstract class NotificationDecorator implements NotificationService {

    protected NotificationService wrappedService;

    public NotificationDecorator(NotificationService service) {
        this.wrappedService = service;
    }

    @Override
    public void send(String message) {
        wrappedService.send(message);
    }
}

This class ensures all decorators wrap another service.


Step 4 — Concrete Decorators

Logging Decorator

public class LoggingDecorator extends NotificationDecorator {

    public LoggingDecorator(NotificationService service) {
        super(service);
    }

    @Override
    public void send(String message) {
        System.out.println("Logging: Notification about to be sent");
        super.send(message);
    }
}

Encryption Decorator

public class EncryptionDecorator extends NotificationDecorator {

    public EncryptionDecorator(NotificationService service) {
        super(service);
    }

    @Override
    public void send(String message) {
        String encryptedMessage = encrypt(message);
        super.send(encryptedMessage);
    }

    private String encrypt(String message) {
        return "***" + message + "***"; // simple mock encryption
    }
}

Step 5 — Client Code

public class Main {
    public static void main(String[] args) {

        NotificationService service =
                new LoggingDecorator(
                        new EncryptionDecorator(
                                new BasicNotificationService()
                        )
                );

        service.send("Payment successful");
    }
}

Output:

Logging: Notification about to be sent
Sending notification: ***Payment successful***

Real-World Usage in Java

Decorator is heavily used in:

  • Java I/O Streams

    Example:

    new BufferedReader(new InputStreamReader(new FileInputStream("file.txt")));
    

    Each layer decorates the stream.

  • Spring AOP

  • Servlet filters

  • Logging wrappers

  • Security wrappers


Decorator vs Strategy

Strategy Decorator
Changes behavior completely Adds extra behavior
Focuses on algorithm selection Focuses on feature extension
Swappable logic Stackable functionality
Used via composition Used via wrapping

Strategy = choose one behavior

Decorator = add multiple enhancements


When NOT to Use Decorator

Avoid when:

  • Only one small extension is needed

  • Simpler inheritance is sufficient

  • Overwrapping makes debugging hard

Too many decorators can make stack traces complex.


Interview Perspective

If asked:

“What problem does Decorator solve?”

Answer:

It allows extending functionality dynamically without modifying existing code.

If asked:

“Where is Decorator used in Java?”

Answer:

Java I/O Streams are a classic example.


Final Thoughts

Decorator Pattern is about:

Extending behavior cleanly, flexibly, and without breaking existing code.

It is extremely practical and widely used in real Java systems.