The Strategy pattern is a behavioral design pattern that enables an object to dynamically change its behavior at runtime by encapsulating different algorithms or strategies within interchangeable objects.
It promotes the principle of composition over inheritance and allows for flexible and modular code. In PHP, the Strategy pattern can be implemented using interfaces and multiple classes that implement those interfaces.
Here is an example implementation in PHP:
// Strategy interface defines the contract for the strategies.
interface PaymentStrategy {
public function pay($amount);
}
// Concrete strategy classes implement the strategy interface.
class CreditCardStrategy implements PaymentStrategy {
private $creditCardNumber;
private $expirationDate;
public function __construct($creditCardNumber, $expirationDate) {
$this->creditCardNumber = $creditCardNumber;
$this->expirationDate = $expirationDate;
}
public function pay($amount) {
echo "Paying $" . $amount . " using credit card " . $this->creditCardNumber . ".<br>";
}
}
class PayPalStrategy implements PaymentStrategy {
private $email;
private $password;
public function __construct($email, $password) {
$this->email = $email;
$this->password = $password;
}
public function pay($amount) {
echo "Paying $" . $amount . " using PayPal account " . $this->email . ".<br>";
}
}
// Context class that uses the strategy.
class ShoppingCart {
private $paymentStrategy;
private $items;
public function __construct() {
$this->items = [];
}
public function addItem($item) {
$this->items[] = $item;
}
public function setPaymentStrategy(PaymentStrategy $paymentStrategy) {
$this->paymentStrategy = $paymentStrategy;
}
public function checkout() {
$totalAmount = $this->calculateTotalAmount();
$this->paymentStrategy->pay($totalAmount);
}
private function calculateTotalAmount() {
// Calculate the total amount based on the items in the shopping cart.
$total = 0;
foreach ($this->items as $item) {
$total += $item['price'];
}
return $total;
}
}
// Usage example:
$shoppingCart = new ShoppingCart();
// Add items to the shopping cart
$shoppingCart->addItem(['name' => 'Item 1', 'price' => 10]);
$shoppingCart->addItem(['name' => 'Item 2', 'price' => 20]);
// Set the payment strategy to credit card
$creditCardStrategy = new CreditCardStrategy('1234567890', '12/2024');
$shoppingCart->setPaymentStrategy($creditCardStrategy);
$shoppingCart->checkout(); // Output: Paying $30 using credit card 1234567890.
// Set the payment strategy to PayPal
$paypalStrategy = new PayPalStrategy(This email address is being protected from spambots. You need JavaScript enabled to view it.', 'password');
$shoppingCart->setPaymentStrategy($paypalStrategy);
$shoppingCart->checkout(); // Output: Paying $30 using PayPal account This email address is being protected from spambots. You need JavaScript enabled to view it..
In this example, we have a PaymentStrategy
interface that defines the contract for different payment strategies. The CreditCardStrategy
and PayPalStrategy
classes implement the PaymentStrategy
interface and provide their own implementations of the pay()
method.
The ShoppingCart
class acts as the context that uses the strategy. It maintains a reference to the selected payment strategy and provides methods for adding items to the shopping cart, setting the payment strategy, and performing the checkout. The calculateTotalAmount()
method calculates the total amount based on the items in the shopping cart, and the checkout()
method delegates the payment to the selected strategy.
In the usage example, we create a ShoppingCart
object and add some items to it. We then set the payment strategy to either a credit card or PayPal and perform the checkout. Depending on the selected strategy, the pay() method of the corresponding strategy class is invoked, resulting in different payment behaviors.
The Strategy pattern allows for easy interchangeability of algorithms or strategies, as well as the addition of new strategies without modifying the existing code. It promotes code reuse, encapsulates algorithm-specific logic, and provides a flexible way to switch between different behaviors at runtime.