Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon Can you provide a detailed example of implementing the Strategy pattern in Laravel
    Laravel Strategy pattern payment methods PaymentStrategy Stripe PayPal SOLID principles PHP design patterns


Can you provide a detailed example of implementing the Strategy pattern in Laravel


Here is a detailed example of implementing the Strategy pattern in a Laravel application:

The Context

Let's say we have an e-commerce application that needs to handle different payment methods. We want to make it easy to add new payment methods in the future without modifying the existing code.

The Strategy Interface

First, we define a `PaymentStrategy` interface that declares the methods common to all payment strategies:

php
namespace App\Strategies;

interface PaymentStrategy
{
    public function pay(float $amount): bool;
    public function getPaymentMethod(): string;
}

Concrete Payment Strategies

Next, we create concrete implementations of the `PaymentStrategy` interface for each payment method:

php
namespace App\Strategies;

class StripePaymentStrategy implements PaymentStrategy
{
    public function pay(float $amount): bool
    {
        // Implement Stripe payment logic
        return true;
    }

    public function getPaymentMethod(): string
    {
        return 'Stripe';
    }
}

php
namespace App\Strategies;

class PaypalPaymentStrategy implements PaymentStrategy
{
    public function pay(float $amount): bool
    {
        // Implement PayPal payment logic
        return true;
    }

    public function getPaymentMethod(): string
    {
        return 'PayPal';
    }
}

The Context Class

The `Context` class is responsible for interacting with the `PaymentStrategy` objects. It holds a reference to the current `PaymentStrategy` and delegates the payment processing to it:

php
namespace App\Services;

use App\Strategies\PaymentStrategy;

class PaymentContext
{
    private $paymentStrategy;

    public function setPaymentStrategy(PaymentStrategy $strategy)
    {
        $this->paymentStrategy = $strategy;
    }

    public function processPayment(float $amount): bool
    {
        return $this->paymentStrategy->pay($amount);
    }

    public function getPaymentMethod(): string
    {
        return $this->paymentStrategy->getPaymentMethod();
    }
}

Usage in a Controller

In a controller, we can use the `PaymentContext` to process payments:

php
namespace App\Http\Controllers;

use App\Services\PaymentContext;
use App\Strategies\StripePaymentStrategy;
use App\Strategies\PaypalPaymentStrategy;

class PaymentController extends Controller
{
    public function processPayment(float $amount)
    {
        $paymentContext = new PaymentContext();

        // Set the payment strategy
        $paymentContext->setPaymentStrategy(new StripePaymentStrategy());

        // Process the payment
        if ($paymentContext->processPayment($amount)) {
            // Payment successful
            return response()->json(['message' => 'Payment successful']);
        } else {
            // Payment failed
            return response()->json(['message' => 'Payment failed'], 500);
        }
    }

    public function changePaymentMethod(float $amount)
    {
        $paymentContext = new PaymentContext();

        // Set a different payment strategy
        $paymentContext->setPaymentStrategy(new PaypalPaymentStrategy());

        // Process the payment with the new strategy
        if ($paymentContext->processPayment($amount)) {
            // Payment successful
            return response()->json(['message' => 'Payment successful']);
        } else {
            // Payment failed
            return response()->json(['message' => 'Payment failed'], 500);
        }
    }
}

By using the Strategy pattern, we can easily switch between different payment methods without modifying the `PaymentContext` class. If we need to add a new payment method in the future, we can create a new concrete `PaymentStrategy` implementation and use it in the `PaymentContext` without changing any existing code.

This promotes the Open/Closed Principle (OCP) of SOLID design principles, as the `PaymentContext` is open for extension (adding new payment methods) but closed for modification.

Citations:
[1] https://ashallendesign.co.uk/blog/using-the-strategy-pattern-in-laravel
[2] https://github.com/robert-knepper/strategyDesignPattern
[3] https://muktar.tech/design-patterns-real-world-examples-in-laravel-django-and-express-js-6a91dce1dbba?gi=96bb15545f94
[4] https://www.reddit.com/r/PHP/comments/1cqetfy/laravel_under_the_hood_the_strategy_pattern/
[5] https://www.youtube.com/watch?v=0VlakXgCukM