0
0
JavaConceptBeginner · 3 min read

Decorator Pattern in Java: What It Is and How It Works

The Decorator Pattern in Java is a design pattern that lets you add new behavior to objects dynamically without changing their original code. It wraps an object inside another object to extend its functionality while keeping the same interface.
⚙️

How It Works

Imagine you have a plain coffee, and you want to add milk or sugar without changing the coffee itself. The decorator pattern works similarly by wrapping an object with another object that adds new features. This wrapping can be done many times, each adding its own behavior.

In Java, this means you create a base interface or class, then create decorators that implement the same interface and hold a reference to the original object. When you call a method, the decorator can add extra steps before or after delegating the call to the original object.

This approach helps keep code flexible and easy to extend without modifying existing classes, which is great for maintaining and scaling software.

💻

Example

This example shows a simple text message that can be decorated to add stars or brackets around it dynamically.

java
interface Message {
    String getContent();
}

class SimpleMessage implements Message {
    private final String content;

    public SimpleMessage(String content) {
        this.content = content;
    }

    @Override
    public String getContent() {
        return content;
    }
}

class MessageDecorator implements Message {
    protected final Message message;

    public MessageDecorator(Message message) {
        this.message = message;
    }

    @Override
    public String getContent() {
        return message.getContent();
    }
}

class StarDecorator extends MessageDecorator {
    public StarDecorator(Message message) {
        super(message);
    }

    @Override
    public String getContent() {
        return "*** " + super.getContent() + " ***";
    }
}

class BracketDecorator extends MessageDecorator {
    public BracketDecorator(Message message) {
        super(message);
    }

    @Override
    public String getContent() {
        return "[" + super.getContent() + "]";
    }
}

public class DecoratorDemo {
    public static void main(String[] args) {
        Message message = new SimpleMessage("Hello");
        System.out.println(message.getContent());

        Message starMessage = new StarDecorator(message);
        System.out.println(starMessage.getContent());

        Message bracketStarMessage = new BracketDecorator(starMessage);
        System.out.println(bracketStarMessage.getContent());
    }
}
Output
Hello *** Hello *** [*** Hello ***]
🎯

When to Use

Use the decorator pattern when you want to add features to objects at runtime without changing their code. It is helpful when subclassing would create too many classes or when you want to combine behaviors flexibly.

Real-world uses include adding scrollbars or borders to windows in graphical user interfaces, adding responsibilities like logging or security checks to objects, or formatting output dynamically.

Key Points

  • The decorator pattern wraps an object to add new behavior.
  • It keeps the same interface so wrapped objects can be used interchangeably.
  • It helps avoid large inheritance trees by composing behaviors.
  • Decorators can be stacked to combine multiple features.

Key Takeaways

The decorator pattern adds behavior to objects dynamically by wrapping them.
It preserves the original object's interface for easy substitution.
Use it to extend functionality without subclassing or modifying existing code.
Decorators can be combined to create flexible and reusable features.