Strategy — ce este, modelul strategie în iOS și Android

Autor: IT Sectr Publicat: 2026-02-18 Timp de citire: 9 min

Strategy (Strategie) — un model comportamental de proiectare care definește o familie de algoritmi interschimbabili și plasează fiecare dintre ei într-o clasă separată (Strategy). Modelul permite alegerea algoritmului din mers: codul client funcționează printr-o interfață comună Strategy, iar implementarea concretă este introdusă în runtime. În iOS modelul se implementează prin Protocol + clase-strategii, în Android — prin Interface + implementări. Strategy — unul dintre cele 23 de modele GoF, utilizat pe scară largă pentru procesarea plăților, validare, sortare și filtrare a datelor. Mai multe — în descrierea originală GoF.

Esențial

  • Strategy — model comportamental GoF pentru o familie de algoritmi interschimbabili
  • Încapsularea algoritmilor — fiecare algoritm este izolat în propria clasă
  • Interfața Strategy — contractul comun implementat de toate strategiile concrete
  • Compoziție în loc de moștenire — contextul păstrează o referință la strategie, nu moștenește comportamentul
  • Principiul Open/Closed — strategii noi se adaugă fără modificarea codului existent

Ce este modelul Strategy: esență și structură

Strategy — unul dintre cele 23 de modele GoF (Gang of Four), descris în cartea «Design Patterns: Elements of Reusable Object-Oriented Software» (1994). Modelul rezolvă problema alegerii algoritmului în runtime. În loc să scrieți o singură clasă cu mulți operatori condiționali (if-else, switch), Strategy propune separarea fiecărui algoritm într-o clasă separată cu o interfață comună. Contextul (clasa care utilizează strategia) păstrează o referință la interfața Strategy și delegă execuția strategiei concrete.

Structura modelului include trei elemente: Context (contextul) conține o referință la Strategy și apelează metoda acesteia; Strategy (interfața) declară o metodă comună pentru toți algoritmii; ConcreteStrategy (strategia concretă) implementează interfața și conține algoritmul concret. Clientul creează strategia necesară și o transmite contextului prin constructor, setter sau parametru de metodă. Contextul nu știe ce strategie se execută — lucrează doar cu interfața.

ComponentăRolExemplu
ContextConține o referință la StrategyPaymentProcessor, Sorter
StrategyInterfață comună pentru algoritmiProtocol PaymentStrategy
ConcreteStrategyImplementare concretă a algoritmuluiCardPayment, PayPalPayment

Principiul Open/Closed — avantajul principal al Strategy. Sistemul este deschis pentru extindere (se poate adăuga o strategie nouă) și închis pentru modificare (nu trebuie modificat codul contextului). Fără model, adăugarea unui nou algoritm necesită modificarea clasei existente, ceea ce încalcă OCP și crește riscul erorilor de regresie. Strategy reduce de asemenea dimensiunea claselor: în loc de o clasă de 200 de rânduri cu switch-case, obțineți 6 clase a câte 20 de rânduri fiecare.

Strategy în iOS: implementare în Swift cu Protocol

Strategy în Swift se implementează prin Protocol (interfața strategiei) și clase sau structuri-strategii. Protocoalele Swift acceptă associated types și generic constraints, ceea ce oferă flexibilitate la proiectarea strategiilor. Contextul este de obicei o clasă ViewModel sau un serviciu care primește strategia în init sau printr-o proprietate. Modelul este utilizat pe scară largă în proiectele iOS pentru procesarea evenimentelor, animații, formatarea datelor și strategii UI.

swift
// 1. Protocol Strategy
protocol PaymentStrategy {
    func pay(amount: Decimal) async throws -> PaymentResult
}

// 2. Strategii concrete
struct CardPaymentStrategy: PaymentStrategy {
    let cardNumber: String
    let cvv: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // Trimiterea cererii către API-ul bancar
        return PaymentResult(status: .success, transactionId: "tx_\(UUID())")
    }
}

struct PayPalPaymentStrategy: PaymentStrategy {
    let email: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // Redirecționare către PayPal SDK
        return PaymentResult(status: .success, transactionId: "pp_\(UUID())")
    }
}

// 3. Context
class PaymentProcessor {
    private var strategy: PaymentStrategy

    init(strategy: PaymentStrategy) {
        self.strategy = strategy
    }

    func setStrategy(_: PaymentStrategy) {
        strategy = strategy
    }

    func processPayment(amount: Decimal) async throws -> PaymentResult {
        return try await strategy.pay(amount: amount)
    }
}

// Utilizare
let processor = PaymentProcessor(strategy: CardPaymentStrategy(cardNumber: "4111...", cvv: "123"))
let result = try await processor.processPayment(amount: 99.99)

Strategy în SwiftUI — modelul se integrează natural cu MVVM. ViewModel conține o proprietate strategie și apelează metoda acesteia la acțiunea utilizatorului. SwiftUI View primește date prin @Published sau @State — strategia ascunde detaliile de implementare de View. De exemplu, strategia de validare a textului (emailValidator, phoneValidator) se schimbă în funcție de tipul câmpului de intrare. Combinarea Strategy cu SwiftUI oferă flexibilitate fără moștenire de la UIKit.

Strategy în Android: implementare în Kotlin cu Interface

Strategy în Kotlin utilizează Interface la nivel de limbaj și interfețe funcționale (SAM) pentru simplificare. Kotlin suportă lambdas, ceea ce permite transmiterea algoritmilor ca funcții fără a declara o clasă separată de strategie. În Android modelul se aplică în ViewModel și Use Cases pentru izolarea algoritmilor de încărcare a datelor, cache și gestionare a erorilor. Proiectele Android cu Clean Architecture folosesc Strategy pentru injectarea diferitelor implementări de repository în funcție de flaguri (mock, real, cache).

kotlin
// 1. Interface Strategy
interface PaymentStrategy {
    suspend fun pay(amount: BigDecimal): PaymentResult
}

// 2. Strategii concrete
class CardPaymentStrategy(
    private val cardNumber: String,
    private val cvv: String
) : PaymentStrategy {
    override suspend fun pay(amount: BigDecimal): PaymentResult {
        // API bancar prin Retrofit
        return PaymentResult(success = true, transactionId = "tx_${UUID.randomUUID()}")
    }
}

class PayPalPaymentStrategy(
    private val email: String
) : PaymentStrategy {
    override suspend fun pay(amount: BigDecimal): PaymentResult {
        // PayPal SDK integration
        return PaymentResult(success = true, transactionId = "pp_${UUID.randomUUID()}")
    }
}

// 3. Context
class PaymentProcessor(
    private val strategy: PaymentStrategy
) {
    fun setStrategy(strategy: PaymentStrategy): PaymentProcessor {
        return PaymentProcessor(strategy)
    }

    suspend fun processPayment(amount: BigDecimal): PaymentResult {
        return strategy.pay(amount)
    }
}

// Utilizare în ViewModel
class CheckoutViewModel : ViewModel() {
    private var processor = PaymentProcessor(CardPaymentStrategy("4111...", "123"))

    fun payWithCard() {
        viewModelScope.launch {
            val result = processor.processPayment(BigDecimal("99.99"))
            // Procesarea rezultatului
        }
    }
}

Strategy cu Hilt/Dagger — în proiectele Android strategiile sunt adesea injectate prin DI. Hilt furnizează implementarea concretă a PaymentStrategy prin @Binds sau @Provides. Acest lucru permite schimbarea strategiei fără modificarea codului contextului — este suficient să schimbați modulul DI pentru un alt build (debug/release). De exemplu, pentru depanare se injectează MockPaymentStrategy, pentru producție — strategia bancară reală. Combinația Strategy + DI oferă flexibilitate maximă.

Comparația Strategy cu State, Command și Template Method

Strategy vs State — structural modelele sunt identice: ambele folosesc compoziție cu interfață și clase concrete. Diferența este în scop: Strategy selectează un algoritm independent, State gestionează comportamentul obiectului în funcție de starea sa. În State contextul schimbă singur strategia la modificarea stării, în Strategy contextul nu controlează comutarea — clientul specifică explicit algoritmul. Strategiile nu știu una de alta, stările pot trece între ele.

Strategy vs Command — Command încapsulează o singură acțiune ca obiect, Strategy încapsulează un set de algoritmi interschimbabili. Command — «ce să faci» (un singur apel execute), Strategy — «cum să faci» (algoritm din mai mulți pași). Command se utilizează pentru cozi, execuție întârziată, undo/redo. Strategy — pentru alegerea modului de executare a sarcinii în runtime. Comenzile pot fi parametrizate cu strategii, combinând ambele modele.

CaracteristicăStrategyStateCommandTemplate Method
ScopAlgoritmi interschimbabiliComportament în funcție de stareÎncapsularea cereriiSchetlet de algoritm
SchimbareExplicit de către clientAutomat de către contextDe către client sau coadăPrin moștenire
NivelObiect (compoziție)Obiect (compoziție)ObiectClasă (moștenire)

Strategy vs Template Method — ambele modele definesc algoritmi, dar în moduri diferite. Template Method folosește moștenirea: clasa de bază definește scheletul algoritmului (metoda șablon), subclasele suprascriu pași individuali. Strategy folosește compoziția: algoritmul este complet externalizat într-o clasă separată. Template Method este mai simplu pentru cazuri cu o structură fixă de algoritm, Strategy — când algoritmii sunt complet diferiți și se pot schimba dinamic.

Exemple reale de utilizare a modelului Strategy

Procesarea plăților — exemplul clasic de Strategy. Coșul unui magazin online conține o listă de produse, iar metoda de plată este aleasă de utilizator. Fiecare metodă (card, PayPal, Apple Pay, Google Pay, criptomonedă) — o strategie separată cu semnătura comună pay(amount). Contextul PaymentProcessor nu știe cum se efectuează exact plata — apelează metoda comună. Adăugarea unei noi metode de plată nu necesită modificarea codului coșului.

Validarea datelor — Strategy se aplică pentru diferite reguli de validare ale aceluiași câmp. EmailValidatorStrategy, PhoneValidatorStrategy, AgeValidatorStrategy implementează interfața comună ValidationStrategy cu metoda validate(input). Formularul de înregistrare utilizează un set de strategii pentru verificarea fiecărui câmp. Strategiile de validare pot fi combinate în lanț (Chain of Responsibility) sau aplicate toate odată într-o buclă. Aceasta înlocuiește verificările lungi if-else cu o colecție de validatori polimorfici.

swift
// Strategia de sortare
protocol SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] where T: Comparable
}

struct QuickSortStrategy: SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] { /* quicksort */ items }
}

struct MergeSortStrategy: SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] { /* mergesort */ items }
}

class SortedDataSource<T> {
    private var strategy: SortingStrategy
    func display(_ items: [T]) { let sorted = strategy.sort(items) }
}

Autentificare — în aplicațiile mobile strategiile de autentificare se schimbă în funcție de furnizor. AuthStrategy cu metodele login(), logout(), getToken() este implementată pentru EmailPasswordAuth, GoogleAuth, AppleAuth, BiometricAuth. Contextul AuthManager primește strategia prin DI sau fabrică. Acest lucru permite adăugarea de noi furnizori de autentificare fără modificarea ecranului de login. Modelul Strategy — baza multor biblioteci OAuth și Firebase Authentication.

Întrebări frecvente

Când să folosim Strategy în loc de if-else?

Strategy este justificat când aveți 3+ algoritmi care se pot schimba sau extinde. Dacă aveți 2 algoritmi și sunt stabili — un simplu if-else este mai puțin costisitor. Folosiți Strategy când algoritmii sunt utilizați în diferite părți ale aplicației, când trebuie să înlocuiți algoritmi în runtime sau când fiecare algoritm necesită propriile dependențe și teste.

Strategy este același lucru cu State?

Nu, sunt modele diferite cu structură similară. Strategy — clientul alege explicit algoritmul, iar strategiile sunt independente. State — obiectul își schimbă singur comportamentul la modificarea stării interne, iar stările pot trece una în alta. În State contextul gestionează schimbarea stării, în Strategy — codul client.

Se poate folosi Strategy fără clase — prin closures?

Da, în Swift și Kotlin strategia poate fi transmisă ca closure sau lambda. Swift: typealias PaymentHandler = (Decimal) async throws -> PaymentResult. Kotlin: typealias PaymentFun = suspend (BigDecimal) -> PaymentResult. Aceasta simplifică codul pentru cazuri simple, dar se pierde denumirea și documentația. Pentru 1-2 algoritmi — closure este suficient, pentru 4+ — clase separate sunt mai bune.

Cum se testează modelul Strategy?

Fiecare strategie este testată cu un test unitar separat cu dependențe mock. Contextul se testează cu o strategie mock — se verifică că contextul apelează metoda strategiei și transmite parametrii corecți. În Swift utilizați XCTest + protocoale pentru mock, în Kotlin — MockK sau Mockito. Avantajul principal: fiecare strategie este testată izolat fără configurare complexă.

Strategy este un model GoF?

Da, Strategy (Strategie) — unul dintre cele 23 de modele descrise în cartea «Design Patterns: Elements of Reusable Object-Oriented Software» (Gamma, Helm, Johnson, Vlissides, 1994). Aparține grupului de modele comportamentale (Behavioral Patterns). Sinonime: Policy (Politică). Codul original de exemplu în Smalltalk-80 este disponibil în ediția originală GoF.

Concluzii

  • Strategy — model comportamental pentru algoritmi interschimbabili cu interfață comună
  • Încapsulare — fiecare algoritm este izolat într-o clasă-strategie separată
  • iOS Swift — implementare prin Protocol, structuri și closures
  • Android Kotlin — implementare prin Interface, lambdas și DI cu Hilt
  • Principiul Open/Closed — strategii noi se adaugă fără modificarea contextului
  • Aplicații — plăți, validare, sortare, autentificare, formatare

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și