The Decorator Design Pattern

The Decorator pattern attaches additional responsibilities to an object dynamically.

Use the Decorator pattern when you need to add responsibilities to individual objects dynamically and transparently, without affecting other objects.

  • TypeStructural
  • Time ComplexityO(n) Linear Time – The time taken grows linearly with the size of the input. Examples include simple search algorithms.
  • Efficiency5
  • Learning Effort

    • Average5
    • Conceptual5
    • Debug and Maintain5
    • Implementation4
    • Prerequisites3
    • Versatility7

Things you should know before you start

  • Inheritance Understanding of inheritance in object-oriented programming.
  • Composition Understanding of object composition to achieve complex functionalities.

Minimal Example

Enhancing a simple coffee object with additional ingredients like milk, sugar, and spices.

interface Coffee {
  cost(): number;
}
class MilkDecorator implements Coffee {
  constructor(private coffee: Coffee) {}
  cost() {
    return this.coffee.cost() + 2;
  }
}
let coffee: Coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
console.log(coffee.cost());

What’s happening in thie example

In this example, we have a SimpleCoffee object that gets decorated with a MilkDecorator. The `clientCode` shows how the cost method reflects the added functionality.

How the Decorator Works

The Decorator pattern allows you to add new functionalities to an object without altering its structure. This pattern creates a set of decorator classes that are used to wrap concrete components.

This is particularly useful for adhering to the Single Responsibility Principle, as it allows functionalities to be divided between classes with unique areas of concern.

Entities in the Decorator Design Pattern

  • ComponentDefines the interface for objects that can have responsibilities added to them dynamically.

    • Component has a one-to-many inherits relationship with ConcreteComponent
    • Component has a one-to-many inherits relationship with Decorator

What to watch out for when using or considering this design pattern.

Avoid using the Decorator pattern for extending classes with lots of little features; it can become cumbersome to create and manage a large number of decorator classes.

Design patterns often confused with the Decorator Design Pattern

The following design patterns are often confused with the Decorator
for various resons.

If you’re exploring solutions, have a look through this list and see if
one of these might be a better fit for your problem.

  • Adapter – The Adapter pattern allows objects with incompatible interfaces to collaborate.

    The Adapter pattern is similar to the Decorator in the following ways.

    • Both are structural design patterns.
    • Both focus on object composition.
  • Here are some notable differences with the Decorator pattern.

    • Decorator adds behavior to an object while keeping its interface intact, whereas Adapter alters the interface to make it compatible.
    • Decorator dynamically composes objects, while Adapter statically combines two different interfaces.
  • Composite – The Composite pattern composes objects into tree structures to represent part-whole hierarchies.

    The Composite pattern is similar to the Decorator in the following ways.

    • Both are structural design patterns.
    • Both deal with object compositions.
  • Here are some notable differences with the Decorator pattern.

    • Decorator focuses on adding responsibilities to objects, while Composite focuses on a tree structure of objects.
    • Decorator enhances individual objects, whereas Composite treats individual objects and composites uniformly.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top