The Decorator Pattern is a structural design pattern that allows you to add new functionality to objects dynamically without altering their structure. It provides a flexible alternative to subclassing for extending object behavior.
- Dynamic Behavior Addition: Add responsibilities to objects at runtime
- Avoids Class Explosion: Prevents creating many subclasses for different combinations
- Single Responsibility: Each decorator handles one specific responsibility
- Flexibility: Mix and match decorators in any combination
- Composition over Inheritance: Uses composition instead of inheritance
// WITHOUT Decorator Pattern - Creates explosion of subclasses
class Coffee { }
class CoffeeWithMilk extends Coffee { }
class CoffeeWithMilkAndCaramel extends Coffee { }
class CoffeeWithMilkAndCaramelAndWhipped extends Coffee { }
// For n features, you need 2^n classes!
// WITH Decorator Pattern - Combine features dynamically
Coffee coffee = new WhippedCreamDecorator(
new CaramelDecorator(
new MilkDecorator(
new SimpleCoffee()
)
)
);Features can be added or removed dynamically without modifying original classes.
Create different combinations without creating new classes.
- Each decorator class has one specific responsibility
- SimpleCoffee handles coffee
- MilkDecorator handles milk addition
- CaramelDecorator handles caramel addition
- Open for extension through new decorators
- Closed for modification (no changes to existing classes)
- Decorators depend on the Coffee interface, not concrete implementations
// Without Decorator - Multiple inheritance hierarchies
class SimpleCoffee extends Coffee { }
class CoffeeWithMilk extends SimpleCoffee { }
class CoffeeWithCaramel extends SimpleCoffee { }
class CoffeeWithMilkAndCaramel extends CoffeeWithMilk { }
class CoffeeWithMilkAndCaramelAndWhipped extends CoffeeWithMilkAndCaramel { }
// Exponential growth!
Coffee coffee = new CoffeeWithMilkAndCaramelAndWhipped(); // Limited combinations// With Decorator - Flexible composition
Coffee coffee = new WhippedCreamDecorator(
new CaramelDecorator(
new MilkDecorator(
new SimpleCoffee()
)
)
);
// Any combination possible!✓ Wrapping Objects: Decorators wrap the original object ✓ Same Interface: Decorators implement the same interface as the wrapped object ✓ Composition: Uses composition instead of inheritance ✓ Runtime Addition: Features added at runtime ✓ Chain of Responsibility: Multiple decorators can wrap each other
| Inheritance | Decoration |
|---|---|
| Static, compile-time | Dynamic, runtime |
| Class explosion | No explosion |
| Rigid | Flexible |
| Hard to modify | Easy to modify |
- Adding features to I/O streams (compression, encryption)
- GUI components with various enhancements
- Coffee shop ordering systems
- Logging/caching layers for methods
- Java's InputStream/OutputStream hierarchy
CoffeeDecorator.java- Coffee add-ons decoratorFileIODecorator.java- Compression and encryption decorators