The Decorator pattern is a structural design pattern that allows you to dynamically add new behaviors to objects by placing them inside wrapper objects. It’s a flexible alternative to subclassing for extending functionality.

Structure

The Decorator pattern consists of the following key components:

  • Component: is an interface for objects that can have responsibilities added to them dynamically and is common for wrapper and wrapped objects
  • Concrete Component: is a class that provides a concrete implementation for the Component interface and can be altered by decorators
  • Decorator: maintains a reference to a Component object that is being wrapped and defines an interface that conforms to the Component interface
  • Concrete Decorator: define extra behaviors that can be added to components dynamically

When to use the Decorator Pattern?

  • When extension by subclassing is impractical or impossible
  • When you want to avoid a class hierarchy bloated with every possible combination of extensions
  • When you want to extend functionality without modifying existing code (Open/Closed Principle)

Implementation Example

The code below demonstrates the implementation of the Decorator design pattern in Java.

The Solution class shows the pattern’s flexibility, creating a simple text object and progressively wrapping it with various decorators to achieve different formatting combinations. This structure allows for the dynamic addition of text styles without modifying existing classes, showcasing the pattern’s power in creating flexible and extensible code for text manipulation.

// client class
public class Solution {

    public static void main(String[] args) {

        Text simpleText = new PlainText("Hello, Decorator Pattern!");
        System.out.println("Plain text: " + simpleText.getContent());

        Text boldText = new BoldTextDecorator(simpleText);
        System.out.println("Bold text: " + boldText.getContent());

        Text italicBoldText = new ItalicTextDecorator(boldText);
        System.out.println("Italic and bold text: " + italicBoldText.getContent());

        Text complexText = new UnderlineTextDecorator(italicBoldText);
        System.out.println("Complex formatted text: " + complexText.getContent());
    }
}

// Component interface
interface Text {

    String getContent();
}

// Concrete Component
class PlainText implements Text {

    private String content;

    public PlainText(String content) {

        this.content = content;
    }

    public String getContent() {

        return content;
    }
}

// Decorator
abstract class TextDecorator implements Text {

    protected Text decoratedText;

    public TextDecorator(Text decoratedText) {

        this.decoratedText = decoratedText;
    }

    public String getContent() {

        return decoratedText.getContent();
    }
}
// Concrete Decorators
class BoldTextDecorator extends TextDecorator {

    public BoldTextDecorator(Text decoratedText) {

        super(decoratedText);
    }

    public String getContent() {

        return "<b>" + super.getContent() + "</b>";
    }
}

class ItalicTextDecorator extends TextDecorator {

    public ItalicTextDecorator(Text decoratedText) {

        super(decoratedText);
    }

    public String getContent() {

        return "<i>" + super.getContent() + "</i>";
    }
}

class UnderlineTextDecorator extends TextDecorator {

    public UnderlineTextDecorator(Text decoratedText) {

        super(decoratedText);
    }

    public String getContent() {

        return "<u>" + super.getContent() + "</u>";
    }
}

The output of the following program will be:

Plain text: Hello, Decorator Pattern!
Bold text: <b>Hello, Decorator Pattern!</b>
Italic and bold text: <i><b>Hello, Decorator Pattern!</b></i>
Complex formatted text: <u><i><b>Hello, Decorator Pattern!</b></i></u>