In this tutorial, we will explore how to implement the Strategy Design Pattern in PHP through a practical example. We will create a simple application that demonstrates how to manage different sorting strategies for an array of numbers.

Understanding the Strategy Design Pattern

The Strategy pattern involves three main components:

  1. Context: This class maintains a reference to a Strategy object and allows clients to set and change the strategy.
  2. Strategy Interface: This interface declares a method that all concrete strategies must implement.
  3. Concrete Strategies: These classes implement the Strategy interface and define specific algorithms.

Example Scenario

Let's consider a scenario where we need to sort an array of numbers using different sorting algorithms: Bubble Sort and Quick Sort. We will implement the Strategy pattern to encapsulate these sorting strategies.

Step 1: Define the Strategy Interface

First, we will create a SortStrategy interface that declares the sorting method.

<?php
interface SortStrategy {
    public function sort(array $data): array;
}
?>

Step 2: Implement Concrete Strategies

Next, we will implement the concrete strategies for Bubble Sort and Quick Sort.

Bubble Sort Strategy

<?php
class BubbleSort implements SortStrategy {
    public function sort(array $data): array {
        $n = count($data);
        for ($i = 0; $i < $n - 1; $i++) {
            for ($j = 0; $j < $n - $i - 1; $j++) {
                if ($data[$j] > $data[$j + 1]) {
                    // Swap
                    $temp = $data[$j];
                    $data[$j] = $data[$j + 1];
                    $data[$j + 1] = $temp;
                }
            }
        }
        return $data;
    }
}
?>

Quick Sort Strategy

<?php
class QuickSort implements SortStrategy {
    public function sort(array $data): array {
        if (count($data) < 2) {
            return $data;
        }
        $left = $right = [];
        reset($data);
        $pivotKey = key($data);
        $pivot = array_shift($data);
        foreach ($data as $k => $v) {
            if ($v < $pivot) {
                $left[$k] = $v;
            } else {
                $right[$k] = $v;
            }
        }
        return array_merge((array)$left, [$pivotKey => $pivot], (array)$right);
    }
}
?>

Step 3: Create the Context Class

Now, we will create a Sorter class that serves as the context. This class will hold a reference to a SortStrategy and will delegate the sorting task to the strategy.

<?php
class Sorter {
    private $strategy;

    public function setStrategy(SortStrategy $strategy) {
        $this->strategy = $strategy;
    }

    public function sort(array $data): array {
        return $this->strategy->sort($data);
    }
}
?>

Step 4: Using the Strategy Pattern

Now we can put everything together and demonstrate how to use the Strategy pattern to sort an array of numbers.

<?php
// Client code
$data = [5, 3, 8, 1, 2];

$sorter = new Sorter();

// Using Bubble Sort
$sorter->setStrategy(new BubbleSort());
echo "Bubble Sort: ";
print_r($sorter->sort($data));

// Using Quick Sort
$sorter->setStrategy(new QuickSort());
echo "Quick Sort: ";
print_r($sorter->sort($data));
?>

Output

When you run the above client code, you will see the sorted arrays printed for both sorting strategies:

Bubble Sort: Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 5 [4] => 8 )
Quick Sort: Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 5 [4] => 8 )

Advantages of Using the Strategy Pattern

AdvantageDescription
FlexibilityEasily switch between different algorithms at runtime.
ReusabilityEncapsulated algorithms can be reused across different contexts.
Single Responsibility PrincipleEach strategy class has a single responsibility.
Open/Closed PrincipleNew sorting algorithms can be added without modifying existing code.

Conclusion

The Strategy Design Pattern is a powerful tool in PHP that promotes clean and maintainable code by separating algorithms from the context in which they are used. By encapsulating different sorting strategies, we can easily switch between them as needed, enhancing the flexibility of our applications.

Learn more with useful resources: