AlgoMaster Logo

Decorator Design Pattern

Ashish

Ashish Pratap Singh

4 min read
Decorator

The Decorator Design Pattern is a structural pattern that lets you dynamically add new behavior or responsibilities to objects without modifying their underlying code.

It’s particularly useful in situations where:

  • You want to extend the functionality of a class without subclassing it.
  • You need to compose behaviors at runtime, in various combinations.
  • You want to avoid bloated classes filled with if-else logic for optional features.

Let’s walk through a real-world example to see how we can apply the Decorator Pattern to build a modular, flexible, and easily composable system for enhancing object functionality.

1. The Problem: Adding Features to a Text Renderer

Imagine you’re building a rich text rendering system (like a simple word processor or a markdown preview tool). At the core of your system is a TextView component that renders plain text on screen.

Soon, product requirements evolve:

  • You need to support bold text
  • Then italic text
  • Then underlined text
  • Then scrollable and bordered text containers
  • And possibly combinations of those (e.g., bold + italic + underlined)

Naive Approach: Subclassing for Every Combination

You might start by creating a base class like this:

And then extend it to support new features:

Bold Text View

Italic Text View

BoldItalicTextView

Why This Approach Quickly Falls Apart

1. Class Explosion

For every new combination of features, you need to create a new subclass:

  • BoldTextViewItalicTextViewUnderlineTextView
  • BoldItalicTextViewBoldUnderlineTextViewItalicUnderlineTextView
  • etc.

This doesn’t scale. With just 4 features, you'd already have to manage up to 15 classes for all possible combinations.

2. Rigid Design

You can't dynamically change features at runtime. Want to turn bold on or off based on user preference? You’ll need conditional logic or object swapping.

3. Violates the Open/Closed Principle

Every time a new feature (like highlight or shadow) is introduced, you need to modify or extend existing classes — which increases the chance of regressions.

What We Really Need

We need a solution that lets us:

  • Add features like bold, italic, underline dynamically and independently
  • Compose features in flexible combinations (e.g., bold + scrollable + bordered)
  • Avoid creating dozens of subclasses for every possible variation
  • Follow the Open/Closed Principle — open for extension, closed for modification

This is exactly where the Decorator Pattern shines.

2. The Decorator Pattern

The Decorator Pattern allows you to add responsibilities to objects dynamically, without altering their structure or modifying their original code.

At its core, the pattern relies on wrapping an object inside another object (a decorator) that implements the same interface and adds new behavior before or after delegating to the wrapped object.

This creates a layered effect, where decorators can be stacked to apply multiple enhancements without creating a complex inheritance tree.

Class Diagram

  • Component (e.g., TextView): Declares the common interface (execute()) for all core and decorated objects
  • ConcreteComponent (e.g., PlainTextView): The base object that can be dynamically decorated
  • BaseDecorator (abstract): Implements the component interface and stores a reference to the component to be decorated
  • ConcreteDecorators (BoldDecoratorItalicDecorator, etc.): Extend the base decorator to add new functionality before/after calling the wrapped component’s method
  • Client: Creates and composes decorators at runtime to achieve the desired combination of behaviors

3. Implementing Decorator Pattern

Let’s implement the Decorator Pattern to enable flexible styling of text elements — such as bold, italic, underline, and combinations of these — all without subclassing or modifying the core text rendering logic.

1. Define the Component Interface

This interface will be used by both the base component and all decorators. It defines the render() method that displays the text.

2. Implement the Concrete Component

This is the base class that renders plain text. It implements the TextView interface and contains the core content to be displayed.

3. Create the Abstract Decorator

This class also implements TextView and holds a reference to another TextView component. It forwards calls to the wrapped component.

4. Implement Concrete Decorators

Each decorator adds a specific formatting layer before or after calling the wrapped component's render() method.

Bold Decorator

Italic Decorator

Underline Decorator

5. Compose Decorators in Client Code

The client composes the desired formatting by wrapping decorators dynamically at runtime. This avoids subclass explosion and provides full control over order and combination.

Output

What We Achieved

  • Dynamic layering: We can add, remove, or combine decorators at runtime
  • Modular design: Each decorator is focused on one formatting feature
  • No class explosion: We avoided creating dozens of subclasses for every combination
  • Open/Closed Principle: New formatting options can be added without modifying existing classes
  • Highly flexible: Any combination and ordering of features is now possible