Decorator Pattern

Posted by Dustin Boston in .

The Decorator Pattern is a structural design pattern that enables dynamic addition of behavior to individual objects without modifying their class, promoting flexibility and reusability in software design.


The Decorator Pattern is a structural design pattern that allows behavior to be added to individual objects dynamically without modifying their class. This pattern promotes flexibility and reusability by enabling the extension of object functionality at runtime. It is particularly useful when you need to adhere to the open/closed principle in software design.

Source Code Listing

code.ts

type Component = {
  add(key: string, value: any): void;
  get(): Record<string, any>;
  process(): void;
};

class ConcreteComponent implements Component {
  private props: Record<string, any> = {}; // Initialize props

  add(key: string, value: any): void {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
    this.props[key] = value;
  }

  get(): Record<string, any> {
    return this.props;
  }

  process(): void {
    console.log("ConcreteComponent processing"); // Or any actual processing logic
  }
}

class Decorator implements Component {
  constructor(protected component: Component) {}

  add(key: string, value: any): void {
    this.component.add(key, value); // Delegate to the wrapped component
  }

  get(): Record<string, any> {
    return this.component.get(); // Delegate to the wrapped component
  }

  process(): void {
    this.component.process(); // Delegate to the wrapped component
  }
}

class ConcreteDecoratorA extends Decorator {
  process(): void {
    this.add("concreteDecoratorAProcess", true);
    super.process(); // Call the wrapped component's process after decoration
    console.log("ConcreteDecoratorA processing");
  }
}

class ConcreteDecoratorB extends Decorator {
  process(): void {
    this.add("concreteDecoratorBProcess", true);
    super.process(); // Call the wrapped component's process after decoration
    console.log("ConcreteDecoratorB processing");
  }
}

const example = {
  run(): void {
    const component: Component = new ConcreteDecoratorA(
      new ConcreteDecoratorB(new ConcreteComponent()),
    );
    component.process();
    console.log(component.get());
  },
};

example.run();