Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

Subscribe to the newsletter

Get new articles and course lessons delivered to your inbox. No spam, unsubscribe anytime.

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 46 of the Intermediate Laravel: Real-World Application Patterns course
LaravelJune 26, 20263 min read

Strategy Pattern for Business Rules in Laravel

Stop writing massive if-else chains for business logic. Learn how to implement the Strategy pattern in Laravel to keep your services clean and extensible.

laraveldesign patternsrefactoringarchitecturesolidphpbackend

Previously in this course, we explored using Value Objects to encapsulate primitive data behavior. While Value Objects handle data integrity, business rules often vary based on context or user input. When you find yourself writing complex switch or if/else statements inside your services, you've hit a wall where the Strategy pattern can help.

The Strategy pattern allows you to define a family of algorithms, encapsulate each one, and make them interchangeable. This lets the algorithm vary independently from the clients that use it.

The Problem: When Logic Becomes a Liability

In our project board application, let's say we need to calculate the "priority score" for a task. Initially, it's a simple calculation. But as we grow, we need different strategies: one for "Urgent" projects, one for "Standard" projects, and perhaps one for "Maintenance" tasks.

If you put this logic in a TaskService, you'll end up with a maintenance nightmare:

PHP
public function calculateScore(Task $task)
{
    if ($task->type === 'urgent') {
        return $task->points * 2;
    } elseif ($task->type === 'maintenance') {
        return $task->points * 0.5;
    }
    return $task->points;
}

As you add more project types, this method grows indefinitely. This violates the Open/Closed Principle—you should be able to add new scoring rules without modifying existing service code.

Defining the Strategy Interface

To fix this, we first define an interface that every scoring strategy must implement. This ensures our service doesn't care how the score is calculated, only that it can be calculated.

PHP
namespace App\Contracts;

use App\Models\Task;

interface TaskScoringStrategy
{
    public function calculate(Task $task): int;
}

Implementing Concrete Strategies

Now, create concrete classes that implement this interface. These are the specific "strategies" for our business rules.

PHP
namespace App\Strategies\Scoring;

use App\Contracts\TaskScoringStrategy;
use App\Models\Task;

class UrgentScoring implements TaskScoringStrategy
{
    public function calculate(Task $task): int
    {
        return $task->points * 2;
    }
}

class MaintenanceScoring implements TaskScoringStrategy
{
    public function calculate(Task $task): int
    {
        return (int) ($task->points * 0.5);
    }
}

Injecting Strategies into Services

Instead of hardcoding logic, our TaskService now depends on the interface. We can inject the specific strategy we need at runtime.

PHP
namespace App\Services;

use App\Contracts\TaskScoringStrategy;
use App\Models\Task;

class TaskService
{
    public function calculateTaskScore(Task $task, TaskScoringStrategy $strategy): int
    {
        return $strategy->calculate($task);
    }
}

By leveraging the Service Layer and proper dependency injection, our service remains thin and focused. We aren't concerned with the implementation details, only the contract.

Hands-on Exercise

  1. Create a DiscountStrategy interface for our project board's subscription module.
  2. Implement two strategies: StandardDiscount (10% off) and EnterpriseDiscount (25% off).
  3. Create a BillingService that accepts a DiscountStrategy in its calculateTotal method and verify it works with a simple test.

Common Pitfalls

  • Over-Engineering: Don't apply the Strategy pattern if you only have one or two simple rules. It adds file overhead. Use it when the number of rules is high or the logic is volatile.
  • Missing the Context: Sometimes, a strategy needs extra data. Ensure your interface methods are flexible enough to accept the necessary context (like the Task model) without making the interface too rigid.
  • Tight Coupling: Ensure your concrete strategies don't become dependent on other services. If a strategy needs database access, inject the Repository into the strategy's constructor.

Recap

The Strategy pattern is your best friend when refactoring complex, conditional business logic. By defining a clear interface, you decouple your service layer from the specific implementation of your rules. This makes your code modular, testable, and significantly easier to extend as your application's requirements evolve.

Up next: We will explore how to manage complex multi-step workflows using Job Batching to keep our background processing resilient.

Previous lessonUsing Value ObjectsNext lesson Advanced Queue Monitoring
Back to Blog

Similar Posts

LaravelJune 26, 20264 min read

Using Value Objects: Encapsulating Domain Logic in Laravel

Learn how to use Value Objects in Laravel to eliminate primitive obsession, encapsulate attribute logic, and improve domain clarity in your models.

Read more
LaravelJune 26, 20263 min read

Project Structure for Large Applications: Domain-Driven Laravel

Stop drowning in a massive 'App' folder. Learn to use domain-driven architecture to organize your Laravel project for long-term scalability and sanity.

Part of the course

Intermediate Laravel: Real-World Application Patterns

intermediate · Lesson 46 of 58

  1. 1

    Architecting for Maintainability

    3 min
  2. 2

    Implementing the Service Layer

    3 min
  3. 3

    Repository Pattern Fundamentals

    3 min
Read more
LaravelJune 26, 20263 min read

Using Observers for Model Lifecycle Hooks in Laravel

Learn how to use Eloquent observers to centralize model lifecycle logic. Stop cluttering services and keep your project board events clean and maintainable.

Read more
  • 4

    Project Board Domain Modeling

    3 min
  • 5

    Advanced Eloquent Scopes and Accessors

    4 min
  • 6

    Service-Oriented Task Management

    3 min
  • 7

    REST API Fundamentals with Sanctum

    3 min
  • 8

    Resource Controllers and API Responses

    3 min
  • 9

    Handling API Validation and Form Requests

    3 min
  • 10

    Implementing Middleware for API Security

    4 min
  • 11

    Database Transactions for Data Integrity

    3 min
  • 12

    Error Handling and Global Exceptions

    3 min
  • 13

    Introduction to Laravel Events and Listeners

    3 min
  • 14

    Asynchronous Processing with Queues

    4 min
  • 15

    Job Chaining and Batching

    3 min
  • 16

    Feature Testing Fundamentals

    4 min
  • 17

    Mocking Services and Repositories in Tests

    3 min
  • 18

    Testing Events and Jobs

    3 min
  • 19

    Database Factories and Seeding

    3 min
  • 20

    API Versioning Strategies

    4 min
  • 21

    Advanced Request Filtering and Sorting

    3 min
  • 22

    Handling File Uploads in REST APIs

    3 min
  • 23

    Real-time Notifications with Broadcasting

    3 min
  • 24

    Using Observers for Model Lifecycle Hooks

    3 min
  • 25

    Implementing Policies for Authorization

    3 min
  • 26

    Customizing Authentication Guards

    3 min
  • 27

    Rate Limiting API Endpoints

    4 min
  • 28

    Eloquent Performance Optimization

    4 min
  • 29

    Caching Strategies for Performance

    4 min
  • 30

    Using Traits for Code Reuse

    3 min
  • 31

    Advanced Dependency Injection with Service Providers

    3 min
  • 32

    Command Line Tools with Artisan

    3 min
  • 33

    Scheduled Tasks and Cron Jobs

    3 min
  • 34

    Integrating Third-Party Services

    3 min
  • 35

    Handling Webhooks

    3 min
  • 36

    Logging and Monitoring

    3 min
  • 37

    Database Migrations Best Practices

    3 min
  • 38

    Advanced Testing: Integration Tests

    4 min
  • 39

    Testing API Authentication

    4 min
  • 40

    Code Quality and Static Analysis

    3 min
  • 41

    Project Structure for Large Applications

    3 min
  • 42

    Environment and Configuration Management

    3 min
  • 43

    Deploying Laravel Applications

    4 min
  • 44

    Database Indexing Strategies

    4 min
  • 45

    Using Value Objects

    4 min
  • 46

    Strategy Pattern for Business Rules

    3 min
  • 47

    Advanced Queue Monitoring

    3 min
  • 48

    Building a Search API

    3 min
  • 49

    Handling Concurrency and Race Conditions

    4 min
  • 50

    API Documentation with OpenAPI

    3 min
  • 51

    Testing with Test Doubles

    3 min
  • 52

    Implementing Multi-Tenancy

    4 min
  • 53

    Refactoring Legacy Code

    4 min
  • 54

    Using Middleware for Feature Flags

    3 min
  • 55

    Building Reusable Packages

    4 min
  • 56

    Performance Profiling

    3 min
  • 57

    Secure API Design

    3 min
  • 58

    Event Sourcing Concepts

    4 min
  • View full course