codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
🎭

Design Patterns

15 / 100 topics
11Introduction to Structural Patterns12Adapter Pattern13Bridge Pattern14Composite Pattern15Decorator Pattern16Facade Pattern17Flyweight Pattern18Proxy Pattern32Practical Exercises for Structural Patterns
Tutorials/Design Patterns/Decorator Pattern
🎭Design Patterns

Decorator Pattern

Updated 2026-05-15
10 min read

Decorator Pattern

Introduction

The Decorator Pattern is a structural design pattern that allows behavior to be added to individual objects, either statically or dynamically, without affecting the behavior of other objects from the same class. This pattern is particularly useful when you want to add responsibilities to an object in a flexible and reusable way.

In this tutorial, we'll explore how the Decorator Pattern works, its benefits, and provide practical examples to illustrate its usage.

Concept

The core idea behind the Decorator Pattern is to wrap an object with another object that adds new functionality. This wrapping can be done dynamically at runtime, allowing for flexible behavior modification without altering the original object's structure or code.

Key Components

  1. Component: The interface or abstract class defining the operations that can be decorated.
  2. Concrete Component: A concrete implementation of the component interface.
  3. Decorator: An abstract class that implements the same interface as the component and holds a reference to a Component object.
  4. Concrete Decorator: Concrete implementations of the decorator, which add specific behaviors.

Benefits

  • Flexibility: New functionalities can be added dynamically without modifying existing code.
  • Reusability: Decorators can be reused across different components.
  • Single Responsibility Principle: Each decorator focuses on a single responsibility, making the system easier to maintain and extend.

Examples

Let's dive into some practical examples to understand how the Decorator Pattern works in action.

Example 1: Basic Decorator Pattern

Suppose we have a simple coffee shop application where we can order different types of coffee. We want to add various condiments (like sugar, milk) to our coffee without altering the base coffee class.

// Component interface
class Coffee {
  cost() {
    return 5; // Base price for coffee
  }

  description() {
    return "Coffee";
  }
}

// Concrete Component
class Espresso extends Coffee {
  constructor() {
    super();
  }

  cost() {
    return 7; // Espresso has a higher base price
  }

  description() {
    return "Espresso";
  }
}

// Decorator
class CondimentDecorator extends Coffee {
  constructor(coffee) {
    super();
    this._coffee = coffee;
  }

  cost() {
    return this._coffee.cost();
  }

  description() {
    return this._coffee.description();
  }
}

// Concrete Decorators
class Milk extends CondimentDecorator {
  constructor(coffee) {
    super(coffee);
  }

  cost() {
    return this._coffee.cost() + 2; // Adding milk increases the price by $2
  }

  description() {
    return `${this._coffee.description()}, Milk`;
  }
}

class Sugar extends CondimentDecorator {
  constructor(coffee) {
    super(coffee);
  }

  cost() {
    return this._coffee.cost() + 1; // Adding sugar increases the price by $1
  }

  description() {
    return `${this._coffee.description()}, Sugar`;
  }
}

### Usage

```jsx
const espresso = new Espresso();
console.log(espresso.description()); // Output: Espresso
console.log(`Cost: $${espresso.cost()}`); // Output: Cost: $7

const milkEspresso = new Milk(new Espresso());
console.log(milkEspresso.description()); // Output: Espresso, Milk
console.log(`Cost: $${milkEspresso.cost()}`); // Output: Cost: $9

const sugarMilkEspresso = new Sugar(new Milk(new Espresso()));
console.log(sugarMilkEspresso.description()); // Output: Espresso, Milk, Sugar
console.log(`Cost: $${sugarMilkEspresso.cost()}`); // Output: Cost: $10

Example 2: Adding Logging to a Function

Another common use case for the Decorator Pattern is adding logging or other cross-cutting concerns to functions.

// Component interface (function)
function simpleFunction() {
  console.log("Executing simple function");
}

// Decorator
function logDecorator(func) {
  return function(...args) {
    console.log(`Before calling ${func.name}`);
    const result = func.apply(this, args);
    console.log(`After calling ${func.name}`);
    return result;
  };
}

// Usage
const decoratedFunction = logDecorator(simpleFunction);
decoratedFunction();

Output

<OutputBlock>
{`Before calling simpleFunction
Executing simple function
After calling simpleFunction`}
</OutputBlock>

What's Next?

Now that you have a good understanding of the Decorator Pattern, you might want to explore other structural patterns like the Facade Pattern. The Facade Pattern simplifies complex subsystems by providing a unified interface.

Stay tuned for more design pattern tutorials on codingstuff.io!

Info

Remember, the key to effective use of the Decorator Pattern is to identify scenarios where you need to add responsibilities dynamically and without modifying existing code.

PreviousComposite PatternNext Facade Pattern

Recommended Gear

Composite PatternFacade Pattern