Decorator Pattern
The Decorator pattern allows behavior to be added to individual objects, dynamically, without affecting the behavior of other objects from the same class.
When to Use:
Use the Decorator pattern when you need to add responsibilities to objects without modifying their code.
Example
// Component Interfaceinterface Coffee { cost(): number; description(): string;}
// Concrete Componentclass BasicCoffee implements Coffee { cost(): number { return 5; }
description(): string { return 'Basic Coffee'; }}
// Decoratorsclass MilkDecorator implements Coffee { private coffee: Coffee;
constructor(coffee: Coffee) { this.coffee = coffee; }
cost(): number { return this.coffee.cost() + 2; }
description(): string { return this.coffee.description() + ', Milk'; }}
class SugarDecorator implements Coffee { private coffee: Coffee;
constructor(coffee: Coffee) { this.coffee = coffee; }
cost(): number { return this.coffee.cost() + 1; }
description(): string { return this.coffee.description() + ', Sugar'; }}
// Usagelet myCoffee = new BasicCoffee();console.log(`${myCoffee.description()} costs $${myCoffee.cost()}`);
myCoffee = new MilkDecorator(myCoffee);console.log(`${myCoffee.description()} costs $${myCoffee.cost()}`);
myCoffee = new SugarDecorator(myCoffee);console.log(`${myCoffee.description()} costs $${myCoffee.cost()}`);
Pros:
- Extends functionality without modifying existing code.
- Combines behaviors in a flexible and reusable way.
Cons:
- Can result in many small objects, leading to complexity.
- Harder to debug because of many layers of decorators.