free-tech

Decorator Design Pattern


The Decorator design pattern is a structural pattern that allows behavior to be added to objects, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is typically used to extend the functionalities of classes in a flexible and reusable way.


Key Concepts


  1. Component Interface: Defines the interface for objects that can have responsibilities added to them dynamically.
  2. Concrete Component: The class to which additional responsibilities can be attached.
  3. Decorator: Maintains a reference to a component object and defines an interface that conforms to the component's interface.
  4. Concrete Decorators: Extend the functionality of the component by adding new behavior.

Example in PHP:


Let's consider an example where we have a Coffee interface and several implementations and decorators.

Step 1: Define the Component Interface

interface Coffee {
    public function getCost(): int;
    public function getDescription(): string;
}


Step 2: Create Concrete Component

class SimpleCoffee implements Coffee {
    public function getCost(): int {
        return 5;
    }

    public function getDescription(): string {
        return "Simple Coffee";
    }
}


Step 3: Create Decorator Base Class

class CoffeeDecorator implements Coffee {
    protected $coffee;

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

    public function getCost(): int {
        return $this->coffee->getCost();
    }

    public function getDescription(): string {
        return $this->coffee->getDescription();
    }
}


Step 4: Create Concrete Decorators

class MilkDecorator extends CoffeeDecorator {
    public function getCost(): int {
        return $this->coffee->getCost() + 2;
    }

    public function getDescription(): string {
        return $this->coffee->getDescription() . ", Milk";
    }
}

class SugarDecorator extends CoffeeDecorator {
    public function getCost(): int {
        return $this->coffee->getCost() + 1;
    }

    public function getDescription(): string {
        return $this->coffee->getDescription() . ", Sugar";
    }
}


Step 5: Usage

// Simple coffee
$someCoffee = new SimpleCoffee();
echo $someCoffee->getCost(); // 5
echo $someCoffee->getDescription(); // Simple Coffee

// Add milk
$someCoffee = new MilkDecorator($someCoffee);
echo $someCoffee->getCost(); // 7
echo $someCoffee->getDescription(); // Simple Coffee, Milk

// Add sugar
$someCoffee = new SugarDecorator($someCoffee);
echo $someCoffee->getCost(); // 8
echo $someCoffee->getDescription(); // Simple Coffee, Milk, Sugar


Explanation

  1. Component Interface: Coffee defines methods getCost and getDescription.
  2. Concrete Component: SimpleCoffee implements the Coffee interface.
  3. Decorator Base Class: CoffeeDecorator implements Coffee and holds an instance of Coffee.
  4. Concrete Decorators: MilkDecorator and SugarDecorator extend CoffeeDecorator and add new functionality.

Benefits


By using the Decorator pattern, you can dynamically enhance the functionality of objects in a flexible and reusable way without modifying their structure.


Similar Articles


Card image

The SOLID Principles

Card image

SQL Injection

Card image

MVC architecture