The Decorator pattern adds behaviors to an object at runtime without altering core structure, by wrapping.

Components

SOLID principles

  1. Single Responsibility Principle (SRP): Each decorator class has a single responsibility.
  2. Open/Closed Principle (OCP): Decorator extends an object function without modifying itself.
  3. Liskov Substitution Principle (LSP): Decorators are interchangeable with the object because they implement the same interface.
  4. Dependency Inversion Principle (DIP): Decorators depend on an abstraction.

Implementation

No Inheritance

Inheritance doesn’t allow wrapping an object at runtime.

Composition

Composition allows a common method on every decorator to execute because decorators hold a reference to the object they are wrapping, forming a chain.

interface Product {
  packing(): void
}

class ProductA implements Product {
  packing(): void {
    console.log("Packing");
  }
}

// Base Decorator
class DecorableProduct implements Product {
  protected product: Product;

  constructor(product: Product) {
    this.product = product;
  }

  packing(): void {
    this.product.packing();
  }
}

// Concrete decorators
class SafetyPackingDecorator extends DecorableProduct {
  packing(): void {
	  console.log("Adding safety packing...");
    this.product.packing();
  }
}

class DecorativePackingDecorator extends DecorableProduct {
  packing(): void {
	  console.log("Adding decorative packing...");
    this.product.packing();
  }
}

// Client
let product = new DecorativePackingDecorator(
	new SafetyPackingDecorator(new ProductA())
)
product.packing()

Go Composition (Embedding)

It allows Anonymous Embedding if: