Decorator Pattern
Add new behaviors to objects dynamically without altering structure
Pattern Overview
🔗 The Decorator Pattern - Dynamic Behavior Enhancement
Attaches new behaviors to objects by placing them inside special wrapper objects. Perfect for extending functionality without inheritance!
- Core Problem Solved:
- Add behavior to objects at runtime
- Avoid rigid inheritance hierarchies
- Combine multiple enhancements flexibly
- Follow Single Responsibility Principle
- Class-based: Traditional decorator with component interfaces
- Function-based: Higher-order functions (HOFs) for enhancement
- Proxy-based: JavaScript Proxy for transparent decoration
- Real-World Applications:
- Express.js middleware (logging, auth, compression)
- React Higher-Order Components (HOCs)
- Coffee shop ordering system (milk, sugar, extras)
- HTTP request/response processing
- Data processing pipelines
- API endpoint enhancement
- Modern Usage Examples:
- Function composition in functional programming
- React hooks for component enhancement
- Python @decorator syntax
- JavaScript Proxy for method interception
Examples:
Data processing - add encryption and logging to basic processor
Input:
new EncryptionDecorator(new LoggingDecorator(processor))Output:
Enhanced processor with encryption and loggingCoffee shop - customize basic coffee with various add-ons
Input:
new WhipCreamDecorator(new MilkDecorator(basicCoffee))Output:
Coffee with milk and whip cream ($3.25)API client - add retry logic and performance timing to network calls
Input:
withRetry(3)(withTiming('api')(fetchData))Output:
Enhanced function with retry and timingDevelopment tools - add logging to existing objects without modification
Input:
createLoggingProxy(calculator, 'Calculator')Output:
Proxied calculator with automatic loggingConcepts
Object WrappingDynamic BehaviorRuntime EnhancementComposition over InheritanceSingle Responsibility
Complexity Analysis
Time:O(1) - per decoration layer
Space:O(n) - for n decorator layers
Implementation
DataProcessorDecorator
Time: O(1) | Space: O(n)
// Class-based Decorator Implementation
interface DataProcessor {
process(data: string): string;
getDescription(): string;
}
class BasicDataProcessor implements DataProcessor {
process(data: string): string {
return data;
}
getDescription(): string {
return 'Basic data processor';
}
}
abstract class DataProcessorDecorator implements DataProcessor {
constructor(protected processor: DataProcessor) {}
process(data: string): string {
return this.processor.process(data);
}
getDescription(): string {
return this.processor.getDescription();
}
}
class EncryptionDecorator extends DataProcessorDecorator {
process(data: string): string {
const processed = super.process(data);
return Buffer.from(processed).toString('base64');
}
getDescription(): string {
return super.getDescription() + ' + Encryption';
}
}