Introduction to Decorator Pattern
Decorator attaches additional responsibilities to an object dynamically. It provides a flexible alternative to subclassing for extending functionality.
The Problem
Adding shipping options through inheritance:
typescript1// Inheritance explosion2class StandardShipment { }3class InsuredShipment extends StandardShipment { }4class SignatureRequiredShipment extends StandardShipment { }5class FragileShipment extends StandardShipment { }67// Combinations multiply classes8class InsuredSignatureShipment extends StandardShipment { }9class InsuredFragileShipment extends StandardShipment { }10class SignatureFragileShipment extends StandardShipment { }11class InsuredSignatureFragileShipment extends StandardShipment { }12// 3 options = 8 combinations!
The Solution: Decorator
Wrap objects to add behavior:
typescript1// Component interface2interface Shipment {3 getDescription(): string;4 getCost(): number;5}67// Concrete component8class StandardShipment implements Shipment {9 constructor(private baseRate: number) {}1011 getDescription(): string {12 return 'Standard Shipment';13 }1415 getCost(): number {16 return this.baseRate;17 }18}1920// Base decorator21abstract class ShipmentDecorator implements Shipment {22 constructor(protected shipment: Shipment) {}2324 getDescription(): string {25 return this.shipment.getDescription();26 }2728 getCost(): number {29 return this.shipment.getCost();30 }31}3233// Concrete decorators34class InsuranceDecorator extends ShipmentDecorator {35 constructor(shipment: Shipment, private insuredValue: number) {36 super(shipment);37 }3839 getDescription(): string {40 return `${this.shipment.getDescription()} + Insurance ($${this.insuredValue})`;41 }4243 getCost(): number {44 return this.shipment.getCost() + this.insuredValue * 0.02;45 }46}4748class SignatureDecorator extends ShipmentDecorator {49 getDescription(): string {50 return `${this.shipment.getDescription()} + Signature Required`;51 }5253 getCost(): number {54 return this.shipment.getCost() + 3.50;55 }56}5758class FragileDecorator extends ShipmentDecorator {59 getDescription(): string {60 return `${this.shipment.getDescription()} + Fragile Handling`;61 }6263 getCost(): number {64 return this.shipment.getCost() + 5.00;65 }66}
Usage
typescript1// Start with base shipment2let shipment: Shipment = new StandardShipment(10.00);3console.log(shipment.getCost()); // 10.0045// Add insurance6shipment = new InsuranceDecorator(shipment, 500);7console.log(shipment.getCost()); // 20.00 (10 + 500*0.02)89// Add signature requirement10shipment = new SignatureDecorator(shipment);11console.log(shipment.getCost()); // 23.501213// Add fragile handling14shipment = new FragileDecorator(shipment);15console.log(shipment.getCost()); // 28.501617console.log(shipment.getDescription());18// "Standard Shipment + Insurance ($500) + Signature Required + Fragile Handling"
Pattern Structure
1┌─────────────────────┐2│ Component │3│ (interface) │4│─────────────────────│5│ + operation() │6└──────────┬──────────┘7 │8 ┌─────┴─────┐9 │ │10┌────▼────┐ ┌────▼──────────────┐11│Concrete │ │ Decorator │12│Component│ │───────────────────│13│ │ │ - component │◄───┐14└─────────┘ │ + operation() │ │15 └────────┬──────────┘ │16 │ │17 ┌─────────┴─────────┐ │18 │ │ │19 ┌──────▼──────┐ ┌───────▼───┐ │20 │ DecoratorA │ │DecoratorB │ │21 │─────────────│ │───────────│ │22 │+ operation()│ │+operation()│ │23 └─────────────┘ └───────────┘ │24 │ │25 └─────────────────────────┘26 (decorators can wrap other decorators)
Key Participants
- Component - Interface for objects that can have responsibilities added
- ConcreteComponent - The object being decorated
- Decorator - Maintains reference to component, delegates to it
- ConcreteDecorator - Adds responsibilities before/after delegating
When to Use Decorator
- Dynamic extension - Add responsibilities at runtime
- Optional features - Mix-and-match combinations
- Avoid inheritance explosion - Too many subclass combinations
- Transparent wrapping - Decorators look like the original object
Logistics Applications
| Decorator | Adds |
|---|---|
| Insurance | Value coverage, premium cost |
| Signature | Delivery confirmation |
| Fragile | Special handling |
| Express | Priority processing |
| Tracking | Real-time updates |
| Gift Wrap | Presentation packaging |
Summary
Decorator enables flexible addition of behavior by wrapping objects. Stack decorators to combine features without creating a class for every combination.