The Decorator pattern is a structural design pattern that allows you to dynamically add behavior to objects without affecting other objects of the same class. It provides a flexible alternative to subclassing for extending functionality. The pattern involves creating a set of decorator classes that are used to wrap concrete components.

Key Characteristics:

  • Dynamic Behavior Addition: Allows for adding new behavior to objects at runtime.
  • Open/Closed Principle: Extends functionality without modifying existing code.
  • Transparency: Ensures that decorated objects can still be used in the same way as undecorated ones.

How It Works:

  1. Component Interface: Defines the interface for objects that can have responsibilities added dynamically.
  2. Concrete Component: Implements the component interface and defines the base behavior.
  3. Decorator: Implements the component interface and maintains a reference to a component object. It forwards requests to the wrapped component and can add additional behavior.
  4. Concrete Decorators: Extend the functionality of the component by adding specific behavior.

Example in PHP:

  // Component Interface
interface Coffee {
    public function cost();
}

// Concrete Component
class SimpleCoffee implements Coffee {
    public function cost() {
        return 5;
    }
}

// Decorator Base Class
abstract class CoffeeDecorator implements Coffee {
    protected $coffee;

    public function __construct(Coffee $coffee) {
        $this->coffee = $coffee;
    }

    public function cost() {
        return $this->coffee->cost();
    }
}

// Concrete Decorator A
class MilkDecorator extends CoffeeDecorator {
    public function cost() {
        return parent::cost() + 2;
    }
}

// Concrete Decorator B
class SugarDecorator extends CoffeeDecorator {
    public function cost() {
        return parent::cost() + 1;
    }
}

// Usage
$coffee = new SimpleCoffee();
echo "Cost of Simple Coffee: $" . $coffee->cost() . "\n"; // Output: Cost of Simple Coffee: $5

$milkCoffee = new MilkDecorator($coffee);
echo "Cost of Coffee with Milk: $" . $milkCoffee->cost() . "\n"; // Output: Cost of Coffee with Milk: $7

$sugarMilkCoffee = new SugarDecorator($milkCoffee);
echo "Cost of Coffee with Milk and Sugar: $" . $sugarMilkCoffee->cost() . "\n"; // Output: Cost of Coffee with Milk and Sugar: $8
  

Explanation:

  1. Component Interface: Coffee defines the cost() method that all concrete components and decorators must implement.
  2. Concrete Component: SimpleCoffee implements the Coffee interface and provides a base implementation for the cost() method.
  3. Decorator Base Class: CoffeeDecorator implements the Coffee interface and contains a reference to a Coffee object. It delegates the cost() call to the wrapped coffee object.
  4. Concrete Decorators: MilkDecorator and SugarDecorator extend CoffeeDecorator to add their specific behavior (e.g., adding the cost of milk or sugar).

Benefits:

  • Flexibility: Allows adding responsibilities to objects dynamically and independently.
  • Scalability: Facilitates adding new functionalities without altering existing code.
  • Reusability: Decorators can be combined and reused in various ways to achieve different functionalities.

Use Cases:

  • UI Components: For adding features like borders, scrollbars, or other enhancements to UI elements.
  • Logging and Monitoring: To add logging or monitoring functionality to existing objects without modifying their code.

The Decorator pattern provides a way to extend the functionality of objects in a flexible and reusable manner, allowing for dynamic changes to behavior without altering the original object.