100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

What is the Decorator Pattern?

Learn the Decorator pattern — dynamic behavior wrapping, stacking, and the open-closed principle — with a Java example and interview Q&A.

mediumQ32 of 226 in Object Oriented Programming Est. time: 5 minsLast updated:
Open Code Lab
32 / 226

Expected Interview Answer

The Decorator pattern attaches additional responsibilities to an object dynamically by wrapping it in one or more decorator objects that share the same interface, giving a flexible alternative to subclassing for extending behavior.

A component interface defines the operations a client can call, and a base implementation provides the default behavior. Decorators implement that same interface, hold a reference to a wrapped component, and forward calls to it while adding behavior before or after the delegation. Because decorators and the base component share a type, they can be stacked in any combination at runtime, producing a wide range of behavior without an explosion of subclasses for every combination. This keeps each responsibility in its own small class and respects the open-closed principle, since new behavior is added by writing a new decorator rather than modifying existing code.

  • Adds behavior at runtime without subclassing
  • Avoids a combinatorial explosion of subclasses
  • Keeps each responsibility in its own focused class
  • Follows the open-closed principle for extension

AI Mentor Explanation

A base bat gives a batter standard willow and grip, and coaches can add protective gear on top — first grip tape, then an anti-scuff sheet, then a toe guard — each layer wrapping the previous one while still functioning as a usable bat. You never rewrite the whole bat manufacturing process to add one accessory; you simply attach the next layer over what already exists. That is the Decorator pattern: each add-on wraps the existing object, adds its own behavior, and still presents the same bat interface to whoever picks it up.

Step-by-Step Explanation

  1. Step 1

    Define a common interface

    The component interface declares the operations both the base object and decorators implement.

  2. Step 2

    Implement the concrete component

    Write the base class with the default behavior clients start from.

  3. Step 3

    Write an abstract decorator

    It implements the same interface and wraps a reference to a component, delegating calls to it.

  4. Step 4

    Stack concrete decorators

    Each concrete decorator adds behavior before or after delegating, and instances can be nested at runtime.

What Interviewer Expects

  • A clear distinction from subclassing (runtime composition vs compile-time hierarchy)
  • Understanding that decorators share the wrapped object's interface
  • A concrete example such as I/O streams or UI widgets
  • Awareness of the open-closed principle connection

Common Mistakes

  • Confusing Decorator with simple inheritance
  • Forgetting the decorator must implement the same interface as the component
  • Not realizing decorators can be stacked in any order at runtime
  • Mixing up Decorator with the Proxy or Adapter patterns

Best Answer (HR Friendly)

The Decorator pattern lets you add new behavior to an object by wrapping it in another object that has the same interface, instead of creating a new subclass for every combination of features. You can stack as many decorators as you need at runtime, which keeps the code flexible and avoids a huge tree of subclasses.

Code Example

Coffee decorator example
interface Beverage {
    double cost();
    String description();
}

class Espresso implements Beverage {
    public double cost() { return 2.0; }
    public String description() { return "Espresso"; }
}

abstract class BeverageDecorator implements Beverage {
    protected Beverage wrapped;
    BeverageDecorator(Beverage wrapped) { this.wrapped = wrapped; }
}

class MilkDecorator extends BeverageDecorator {
    MilkDecorator(Beverage wrapped) { super(wrapped); }
    public double cost() { return wrapped.cost() + 0.5; }
    public String description() { return wrapped.description() + " + Milk"; }
}

Beverage drink = new MilkDecorator(new Espresso());
System.out.println(drink.description() + " = " + drink.cost());

Follow-up Questions

  • How does the Decorator pattern differ from the Proxy pattern?
  • How does Java's I/O stream design use the Decorator pattern?
  • Why does Decorator avoid a subclass explosion?
  • Can decorators be removed or reordered after they are applied?

MCQ Practice

1. The Decorator pattern primarily solves which problem?

Decorator adds behavior to an object at runtime by wrapping it, avoiding a rigid subclass hierarchy.

2. A decorator class must do which of the following?

Decorators implement the component interface and hold a reference to the wrapped instance, enabling stacking.

3. A well-known real-world use of Decorator is?

Java I/O streams wrap readers/writers with decorators like BufferedReader to add buffering behavior.

Flash Cards

Decorator pattern in one line?Wrap an object in another object sharing its interface to add behavior dynamically.

Alternative it avoids?A subclass explosion from hardcoding every feature combination.

What must a decorator implement?The same interface as the component it wraps.

Real-world example?Java I/O stream wrappers like BufferedReader and InputStreamReader.

1 / 4

Continue Learning