# Decorator Pattern

> Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

## Problem

You have a `BaseCoffee` and want to add optional extras — milk, sugar, whipped cream — in any combination. Creating a subclass for every combination (CoffeeWithMilk, CoffeeWithMilkAndSugar, ...) leads to a class explosion.

## Solution

Define a `Coffee` interface. `BaseCoffee` implements it. Each decorator (Milk, Sugar) also implements `Coffee` and wraps another `Coffee`, adding its own cost/description on top.

```
┌───────────────────────┐
│  Coffee (interface)   │
│  + cost(): float      │
│  + description(): str │
└───────┬───────────────┘
        │
   ┌────┴─────────┐
   │              │
┌──┴──────┐  ┌───┴───────────────┐
│BaseCoffee│  │CoffeeDecorator    │
│         │  │ + wrapped: Coffee  │
└─────────┘  └───┬───────────────┘
                 │
          ┌──────┴───────┐
          │              │
     ┌────┴────┐   ┌────┴────┐
     │  Milk   │   │  Sugar  │
     └─────────┘   └─────────┘
```

## When to Use

- You need to add behavior to individual objects at runtime, not the whole class.
- Extension by subclassing is impractical due to too many combinations.
- You want to stack multiple independent behaviors.

## When to Avoid

- Order of decoration matters and is hard to control — consider Chain of Responsibility.
- The wrapped object's identity matters (e.g., `isinstance` checks break).
- You only have one fixed enhancement — just use simple inheritance.

## Pseudocode

```
interface Coffee:
    method cost(): float
    method description(): string

class BaseCoffee implements Coffee:
    method cost(): return 2.00
    method description(): return "Plain coffee"

class MilkDecorator implements Coffee:
    field wrapped: Coffee
    constructor(coffee):
        this.wrapped = coffee
    method cost(): return wrapped.cost() + 0.50
    method description(): return wrapped.description() + ", milk"

class SugarDecorator implements Coffee:
    field wrapped: Coffee
    constructor(coffee):
        this.wrapped = coffee
    method cost(): return wrapped.cost() + 0.25
    method description(): return wrapped.description() + ", sugar"

// Usage
coffee = BaseCoffee()
coffee = MilkDecorator(coffee)
coffee = SugarDecorator(coffee)
print coffee.description() + " => $" + coffee.cost()
```

## Python

```python
from abc import ABC, abstractmethod


class Coffee(ABC):
    """Component interface."""

    @abstractmethod
    def cost(self) -> float: ...

    @abstractmethod
    def description(self) -> str: ...


class BaseCoffee(Coffee):
    """Concrete component."""

    def cost(self) -> float:
        return 2.00

    def description(self) -> str:
        return "Plain coffee"


class CoffeeDecorator(Coffee):
    """Base decorator."""

    def __init__(self, wrapped: Coffee) -> None:
        self._wrapped = wrapped

    def cost(self) -> float:
        return self._wrapped.cost()

    def description(self) -> str:
        return self._wrapped.description()


class MilkDecorator(CoffeeDecorator):
    def cost(self) -> float:
        return super().cost() + 0.50

    def description(self) -> str:
        return super().description() + ", milk"


class SugarDecorator(CoffeeDecorator):
    def cost(self) -> float:
        return super().cost() + 0.25

    def description(self) -> str:
        return super().description() + ", sugar"


class WhipDecorator(CoffeeDecorator):
    def cost(self) -> float:
        return super().cost() + 0.75

    def description(self) -> str:
        return super().description() + ", whipped cream"


if __name__ == "__main__":
    # Plain coffee
    coffee: Coffee = BaseCoffee()
    print(f"{coffee.description()} => ${coffee.cost():.2f}")

    # Add milk
    coffee = MilkDecorator(coffee)
    print(f"{coffee.description()} => ${coffee.cost():.2f}")

    # Add sugar
    coffee = SugarDecorator(coffee)
    print(f"{coffee.description()} => ${coffee.cost():.2f}")

    # Add whipped cream
    coffee = WhipDecorator(coffee)
    print(f"{coffee.description()} => ${coffee.cost():.2f}")

    # Build a different combo from scratch
    print("\n--- Double milk, no sugar ---")
    other: Coffee = MilkDecorator(MilkDecorator(BaseCoffee()))
    print(f"{other.description()} => ${other.cost():.2f}")
```

**Output:**
```
Plain coffee => $2.00
Plain coffee, milk => $2.50
Plain coffee, milk, sugar => $2.75
Plain coffee, milk, sugar, whipped cream => $3.50

--- Double milk, no sugar ---
Plain coffee, milk, milk => $3.00
```

## Go

```go
package main

import "fmt"

// Coffee is the component interface.
type Coffee interface {
	Cost() float64
	Description() string
}

// BaseCoffee is the concrete component.
type BaseCoffee struct{}

func (b *BaseCoffee) Cost() float64        { return 2.00 }
func (b *BaseCoffee) Description() string   { return "Plain coffee" }

// MilkDecorator adds milk.
type MilkDecorator struct{ wrapped Coffee }

func WithMilk(c Coffee) *MilkDecorator       { return &MilkDecorator{wrapped: c} }
func (m *MilkDecorator) Cost() float64       { return m.wrapped.Cost() + 0.50 }
func (m *MilkDecorator) Description() string { return m.wrapped.Description() + ", milk" }

// SugarDecorator adds sugar.
type SugarDecorator struct{ wrapped Coffee }

func WithSugar(c Coffee) *SugarDecorator      { return &SugarDecorator{wrapped: c} }
func (s *SugarDecorator) Cost() float64       { return s.wrapped.Cost() + 0.25 }
func (s *SugarDecorator) Description() string { return s.wrapped.Description() + ", sugar" }

// WhipDecorator adds whipped cream.
type WhipDecorator struct{ wrapped Coffee }

func WithWhip(c Coffee) *WhipDecorator       { return &WhipDecorator{wrapped: c} }
func (w *WhipDecorator) Cost() float64       { return w.wrapped.Cost() + 0.75 }
func (w *WhipDecorator) Description() string { return w.wrapped.Description() + ", whipped cream" }

func printCoffee(c Coffee) {
	fmt.Printf("%s => $%.2f\n", c.Description(), c.Cost())
}

func main() {
	var coffee Coffee = &BaseCoffee{}
	printCoffee(coffee)

	coffee = WithMilk(coffee)
	printCoffee(coffee)

	coffee = WithSugar(coffee)
	printCoffee(coffee)

	coffee = WithWhip(coffee)
	printCoffee(coffee)

	fmt.Println("\n--- Double milk, no sugar ---")
	other := WithMilk(WithMilk(&BaseCoffee{}))
	printCoffee(other)
}
```

**Output:**
```
Plain coffee => $2.00
Plain coffee, milk => $2.50
Plain coffee, milk, sugar => $2.75
Plain coffee, milk, sugar, whipped cream => $3.50

--- Double milk, no sugar ---
Plain coffee, milk, milk => $3.00
```

## JavaScript

```javascript
class BaseCoffee {
  cost() {
    return 2.0;
  }
  description() {
    return "Plain coffee";
  }
}

class MilkDecorator {
  constructor(coffee) {
    this._wrapped = coffee;
  }
  cost() {
    return this._wrapped.cost() + 0.5;
  }
  description() {
    return this._wrapped.description() + ", milk";
  }
}

class SugarDecorator {
  constructor(coffee) {
    this._wrapped = coffee;
  }
  cost() {
    return this._wrapped.cost() + 0.25;
  }
  description() {
    return this._wrapped.description() + ", sugar";
  }
}

class WhipDecorator {
  constructor(coffee) {
    this._wrapped = coffee;
  }
  cost() {
    return this._wrapped.cost() + 0.75;
  }
  description() {
    return this._wrapped.description() + ", whipped cream";
  }
}

function printCoffee(c) {
  console.log(`${c.description()} => $${c.cost().toFixed(2)}`);
}

// --- Main ---
let coffee = new BaseCoffee();
printCoffee(coffee);

coffee = new MilkDecorator(coffee);
printCoffee(coffee);

coffee = new SugarDecorator(coffee);
printCoffee(coffee);

coffee = new WhipDecorator(coffee);
printCoffee(coffee);

console.log("\n--- Double milk, no sugar ---");
const other = new MilkDecorator(new MilkDecorator(new BaseCoffee()));
printCoffee(other);
```

**Output:**
```
Plain coffee => $2.00
Plain coffee, milk => $2.50
Plain coffee, milk, sugar => $2.75
Plain coffee, milk, sugar, whipped cream => $3.50

--- Double milk, no sugar ---
Plain coffee, milk, milk => $3.00
```

## Related Patterns

- **Proxy** — Both wrap an object. Proxy controls access (security, caching, lazy loading); Decorator adds behavior. Proxy usually keeps the same interface; Decorator may enhance it.
- **Chain of Responsibility** — A chain of Decorators is effectively a Chain of Responsibility where every handler processes and passes on.
- **Composite** — Decorator is a degenerate Composite with exactly one child component.
- **Strategy** — Decorator adds behavior to an object; Strategy swaps the algorithm inside an object.
- **Adapter** — Adapter changes the interface; Decorator preserves it while adding behavior.
