Dhananjay Patel Logo
  1. Home
  2. / Blog
  3. / Design Pattern
  4. / Lessons
  5. / 2

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 Interface
interface Coffee {
cost(): number;
description(): string;
}
// Concrete Component
class BasicCoffee implements Coffee {
cost(): number {
return 5;
}
description(): string {
return 'Basic Coffee';
}
}
// Decorators
class 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';
}
}
// Usage
let 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.