design patterns ·
Decorator
Attaches additional responsibilities to an object dynamically by wrapping it in decorator objects.
Theory
Explanation
Intuition first, formal definition second. Skim the bullets if you already know this; read the prose if you don't.
When you need to add behavior to individual objects (not all instances of a class), wrap them in decorator objects that implement the same interface and delegate to the wrapped object while adding behavior before/after.
Decorators implement the same interface as the component they wrap. Each decorator holds a reference to the component and delegates calls to it, adding behavior before or after the delegation. Decorators can wrap other decorators.
When to use
Java I/O streams, adding logging/caching/auth to services, extending UI components without subclassing, middleware stacks - any time you need to add behavior to individual objects at runtime.
When not to
When you need to add behavior to all instances of a class - subclass or modify the class instead.
Key insights
- Java's InputStream → BufferedInputStream → DataInputStream is the canonical Decorator example
- Each decorator adds exactly one responsibility - single responsibility per decorator
- Decorator and Proxy have similar structures but different intents: Decorator adds behavior, Proxy controls access
- Recursive wrapping is the mechanism: decorator wraps decorator wraps concrete component