Design Pattern

Decorator Pattern

Clean Java-only production-ready implementation.


What Problem It Solves

You need to add responsibilities to an object dynamically without modifying the original class. Subclassing every combination is explosive (BaseLogger + TimestampLogger + JSONLogger + EncryptionLogger = 2^N classes). Decorator wraps the original and adds behavior transparently.

Decorator vs Inheritance

AspectInheritanceDecorator
Number of classes2^N combinators (explosive)N decorators + 1 component
FlexibilityStatic (compile-time)Dynamic (runtime-composable)
StackingCan't stack multiple featuresStack any combination
TransparencyNew subclass per variantSame interface, transparent wrapping

Where Decorator Appears in LLD Problems

  • Logger (#15): Add timestamp, log level, JSON format, encryption โ€” stack decorators
  • Notification (#18): Add retry, batching, throttling, encryption as decorators around base channel
  • Middleware (many): HTTP middleware wrapping request handler (auth โ†’ logging โ†’ rate limit โ†’ handler)
  • Pizza/Coffee customization (classic LLD example, not in problem list but commonly asked): size + toppings as decorators

Implementation

// โ”€โ”€โ”€ EXAMPLE 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// WHAT WE ARE IMPLEMENTING:
// A database stream writer wrapping files with Compression and Encryption
// layers at runtime.
//
// WHERE THE DECORATOR FITS IN:
// DataStream is the Component. FileDataStream is the Concrete Component.
// DataStreamDecorator is the base Decorator class wrapped by
// EncryptionDecorator.
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// --- Component ---
interface Logger {
    void log(String message);
}

// --- Concrete component ---
class SimpleLogger implements Logger {
    public void log(String message) {
        System.out.println(message);
    }
}

// --- Base decorator ---
abstract class LoggerDecorator implements Logger {
    protected final Logger wrapped;

    public LoggerDecorator(Logger wrapped) { this.wrapped = wrapped; }

    public void log(String message) {
        wrapped.log(message);  // Default: delegate
    }
}

// --- Concrete decorators ---
class TimestampDecorator extends LoggerDecorator {
    public TimestampDecorator(Logger wrapped) { super(wrapped); }

    public void log(String message) {
        super.log("[2025-01-15 10:30:00] " + message);
    }
}

class JsonDecorator extends LoggerDecorator {
    public JsonDecorator(Logger wrapped) { super(wrapped); }

    public void log(String message) {
        super.log("{"message": "" + message + "", "level": "INFO"}");
    }
}

class EncryptionDecorator extends LoggerDecorator {
    public EncryptionDecorator(Logger wrapped) { super(wrapped); }

    public void log(String message) {
        String encrypted = "encrypted(" + message + ")";
        super.log(encrypted);
    }
}

public class Main {
    public static void main(String[] args) {
        // Compose decorators at runtime
        Logger logger = new TimestampDecorator(
                          new JsonDecorator(
                            new EncryptionDecorator(
                              new SimpleLogger())));

        logger.log("User login successful");
        // Output: [2025-01-15 10:30:00] {"message": "encrypted(User login successful)", "level": "INFO"}
    }
}

๐Ÿ’ฌReview

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...