Strategy Pattern – înlocuirea algoritmilor în runtime

  • Doru Bulubasa
  • 19 January 2026

În aplicațiile reale, apar frecvent situații în care același tip de operație trebuie realizat în moduri diferite, în funcție de context:

  • calcularea prețului final (discount standard, promoțional, VIP)

  • procesarea plăților (card, PayPal, transfer bancar)

  • validări diferite pentru același formular

  • algoritmi diferiți de sortare sau filtrare

O abordare naivă duce rapid la:

if (type == A) { ... }
else if (type == B) { ... }
else if (type == C) { ... }

👉 Strategy Pattern rezolvă elegant această problemă.


Ce este Strategy Pattern?

Strategy Pattern este un behavioral design pattern care:

  • definește o familie de algoritmi

  • îi încapsulează în clase separate

  • îi face interschimbabili în runtime

  • elimină if / switch-urile din codul clientului

📌 Pe scurt:

comportamentul se schimbă, fără să modifici clasa care îl folosește.


Structura pattern-ului

Strategy Pattern are 3 componente principale:

  1. Strategy (interfață) – definește contractul algoritmului

  2. ConcreteStrategy – implementări diferite ale algoritmului

  3. Context – folosește o strategie, fără să știe detalii despre implementare

Client → Context → Strategy
                    ↑
          ConcreteStrategyA
          ConcreteStrategyB


Exemplu practic: calculul prețului final

Scenariu

Avem un magazin online care aplică diferite strategii de calcul al prețului:

  • preț standard

  • discount procentual

  • discount fix


1️⃣ Interfața Strategy

public interface IPricingStrategy
{
    decimal CalculatePrice(decimal basePrice);
}

Aceasta definește algoritmul care poate varia.


2️⃣ Implementări concrete (Concrete Strategies)

Preț standard (fără discount)

public class StandardPricingStrategy : IPricingStrategy
{
    public decimal CalculatePrice(decimal basePrice)
    {
        return basePrice;
    }
}

Discount procentual

public class PercentageDiscountStrategy : IPricingStrategy
{
    private readonly decimal _percentage;

    public PercentageDiscountStrategy(decimal percentage)
    {
        _percentage = percentage;
    }

    public decimal CalculatePrice(decimal basePrice)
    {
        return basePrice - (basePrice * _percentage);
    }
}

Discount fix

public class FixedDiscountStrategy : IPricingStrategy
{
    private readonly decimal _discountAmount;

    public FixedDiscountStrategy(decimal discountAmount)
    {
        _discountAmount = discountAmount;
    }

    public decimal CalculatePrice(decimal basePrice)
    {
        return Math.Max(0, basePrice - _discountAmount);
    }
}


3️⃣ Contextul

Contextul nu știe ce strategie concretă folosește, ci doar interfața.

public class PriceCalculator
{
    private IPricingStrategy _pricingStrategy;

    public PriceCalculator(IPricingStrategy pricingStrategy)
    {
        _pricingStrategy = pricingStrategy;
    }

    public void SetStrategy(IPricingStrategy pricingStrategy)
    {
        _pricingStrategy = pricingStrategy;
    }

    public decimal Calculate(decimal basePrice)
    {
        return _pricingStrategy.CalculatePrice(basePrice);
    }
}


4️⃣ Utilizare – schimbarea strategiei în runtime

var calculator = new PriceCalculator(
    new StandardPricingStrategy()
);

decimal basePrice = 100m;
Console.WriteLine(calculator.Calculate(basePrice)); // 100

calculator.SetStrategy(
    new PercentageDiscountStrategy(0.1m)
);
Console.WriteLine(calculator.Calculate(basePrice)); // 90

calculator.SetStrategy(
    new FixedDiscountStrategy(25)
);
Console.WriteLine(calculator.Calculate(basePrice)); // 75

🎯 Fără if, fără switch, fără modificări în PriceCalculator.


Integrare cu Dependency Injection (ASP.NET / .NET)

În aplicațiile reale, strategiile pot fi rezolvate din DI container:

services.AddTransient<StandardPricingStrategy>();
services.AddTransient<PercentageDiscountStrategy>();
services.AddTransient<FixedDiscountStrategy>();

Sau selectate dinamic pe baza contextului (user, request, config).


Avantaje

✅ elimină codul condițional

✅ respectă principiul Open/Closed

✅ ușor de testat (mock pe interfață)

✅ comportament schimbabil în runtime

✅ cod mai curat și extensibil


Dezavantaje

⚠️ număr mai mare de clase

⚠️ poate fi overkill pentru logică foarte simplă

⚠️ clientul trebuie să știe ce strategie să aleagă


Când să folosești Strategy Pattern?

✔ când ai mai mulți algoritmi pentru aceeași operație

✔ când vrei să eviți if / switch complexe

✔ când comportamentul trebuie schimbat dinamic

✔ când lucrezi cu reguli de business variabile


Concluzie

Strategy Pattern este una dintre cele mai folosite și utile structuri din aplicațiile .NET moderne.

Te ajută să separi ce faci de cum faci, păstrând codul flexibil, testabil și ușor de extins.

☕ Dacă vrei aplicații curate și scalabile, Strategy Pattern trebuie să fie în arsenalul tău de bază.

Scrie un comentariu

Adresa de mail nu va fi publicata. Campurile obligatorii sunt marcate cu *