Skip to main content

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
🔍 Three Implementation Approaches:
  • 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 logging
Coffee 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 timing
Development tools - add logging to existing objects without modification
Input:
createLoggingProxy(calculator, 'Calculator')
Output:
Proxied calculator with automatic logging

Concepts

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';
  }
}