Strategy (Strategiya) — bir-birini əvəz edən alqoritmlər ailəsini təyin edən və hər birini ayrıca sinfə (Strategy) yerləşdirən davranış dizayn nümunəsidir. Nümunə alqoritmi anında seçməyə imkan verir: müştəri kodu ümumi Strategy interfeysi vasitəsilə işləyir, konkret tətbiq isə icra zamanı əlavə olunur. iOS-da nümunə Protocol + strategiya sinifləri vasitəsilə, Android-də isə Interface + tətbiqlər vasitəsilə reallaşdırılır. Strategy — 23 GoF nümunəsindən biri, ödənişlərin işlənməsi, valyudasiya, çeşidləmə və məlumatların filtrasiyası üçün geniş tətbiq olunur. Ətraflı — GoF orijinal təsvirində.
Əsas
Strategy — 23 GoF (Gang of Four) nümunəsindən biri, «Design Patterns: Elements of Reusable Object-Oriented Software» (1994) kitabında təsvir edilmişdir. Nümunə icra zamanı alqoritm seçimi problemini həll edir. Çoxsaylı şərt operatorları (if-else, switch) olan bir sinif yazmaq əvəzinə, Strategy hər alqoritmin ümumi interfeyslə ayrıca sinfə ayrılmasını təklif edir. Kontekst (strategiyadan istifadə edən sinif) Strategy interfeysinə istinad saxlayır və icranı konkret strategiyaya həvalə edir.
Nümunənin strukturu üç elementi əhatə edir: Context (kontekst) Strategy-ə istinad saxlayır və onun metodunu çağırır; Strategy (interfeys) bütün alqoritmlər üçün ümumi metodu bəyan edir; ConcreteStrategy (konkret strategiya) interfeysi tətbiq edir və konkret alqoritmi ehtiva edir. Müştəri lazım olan strategiyanı yaradır və onu konstruktor, setter və ya metod parametri vasitəsilə kontekstə ötürür. Kontekst hansı strategiyanın icra edildiyini bilmir — yalnız interfeyslə işləyir.
| Komponent | Rol | Nümunə |
|---|---|---|
| Context | Strategy-ə istinad saxlayır | PaymentProcessor, Sorter |
| Strategy | Alqoritmlər üçün ümumi interfeys | Protocol PaymentStrategy |
| ConcreteStrategy | Alqoritmin konkret tətbiqi | CardPayment, PayPalPayment |
Open/Closed prinsipi — Strategy-nin əsas üstünlüyü. Sistem genişləndirməyə açıqdır (yeni strategiya əlavə etmək olar) və dəyişikliyə qapalıdır (kontekst kodunu dəyişmək lazım deyil). Nümunəsiz yeni alqoritmin əlavə edilməsi mövcud sinfin dəyişdirilməsini tələb edir, bu da OCP-ni pozur və reqressiv səhvlər riskini artırır. Strategy həmçinin siniflərin ölçüsünü azaldır: 200 sətirlik switch-case sinfi əvəzinə hər biri 20 sətir olan 6 sinif alınır.
Swift-də Strategy Protocol (strategiya interfeysi) və sinif və ya struktur-strategiyalar vasitəsilə tətbiq edilir. Swift protokolları associated types və generic constraints dəstəkləyir, bu da strategiyaların layihələndirilməsində çeviklik verir. Kontekst adətən ViewModel sinfi və ya strategiyanı init və ya xassə vasitəsilə qəbul edən xidmətdir. Nümunə iOS layihələrində hadisələrin işlənməsi, animasiyalar, məlumatların formatlaşdırılması və UI strategiyaları üçün geniş istifadə olunur.
// 1. Protocol Strategy
protocol PaymentStrategy {
func pay(amount: Decimal) async throws -> PaymentResult
}
// 2. Konkret strategiyalar
struct CardPaymentStrategy: PaymentStrategy {
let cardNumber: String
let cvv: String
func pay(amount: Decimal) async throws -> PaymentResult {
// Bank API-sinə sorğu göndərilməsi
return PaymentResult(status: .success, transactionId: "tx_\(UUID())")
}
}
struct PayPalPaymentStrategy: PaymentStrategy {
let email: String
func pay(amount: Decimal) async throws -> PaymentResult {
// PayPal SDK-ya yönləndirmə
return PaymentResult(status: .success, transactionId: "pp_\(UUID())")
}
}
// 3. Kontekst
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)
}
}
// İstifadə
let processor = PaymentProcessor(strategy: CardPaymentStrategy(cardNumber: "4111...", cvv: "123"))
let result = try await processor.processPayment(amount: 99.99)
SwiftUI-də Strategy — nümunə MVVM ilə təbii şəkildə inteqrasiya olunur. ViewModel strategiya xassəsini ehtiva edir və istifadəçi hərəkəti zamanı onun metodunu çağırır. SwiftUI View @Published və ya @State vasitəsilə məlumat alır — strategiya tətbiq detallarını View-dən gizlədir. Məsələn, mətn validasiyası strategiyası (emailValidator, phoneValidator) giriş sahəsinin növündən asılı olaraq dəyişdirilir. Strategy-nin SwiftUI ilə birləşməsi UIKit-dən varislik olmadan çeviklik verir.
Kotlin-də Strategy dil səviyyəsində Interface və sadələşdirmə üçün funksional interfeyslərdən (SAM) istifadə edir. Kotlin lambdaları dəstəkləyir ki, bu da ayrıca strategiya sinfi elan etmədən alqoritmləri funksiya kimi ötürməyə imkan verir. Android-də nümunə ViewModel və Use Cases-də məlumat yükləmə, keşləmə və xəta idarəetmə alqoritmlərinin təcrid edilməsi üçün tətbiq olunur. Clean Architecture ilə Android layihələri bayraqlardan (mock, real, cache) asılı olaraq repozitoriyanın müxtəlif tətbiqlərini inyeksiya etmək üçün Strategy-dən istifadə edir.
// 1. Interface Strategy
interface PaymentStrategy {
suspend fun pay(amount: BigDecimal): PaymentResult
}
// 2. Konkret strategiyalar
class CardPaymentStrategy(
private val cardNumber: String,
private val cvv: String
) : PaymentStrategy {
override suspend fun pay(amount: BigDecimal): PaymentResult {
// Retrofit vasitəsilə Bank API
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. Kontekst
class PaymentProcessor(
private val strategy: PaymentStrategy
) {
fun setStrategy(strategy: PaymentStrategy): PaymentProcessor {
return PaymentProcessor(strategy)
}
suspend fun processPayment(amount: BigDecimal): PaymentResult {
return strategy.pay(amount)
}
}
// ViewModel-də istifadə
class CheckoutViewModel : ViewModel() {
private var processor = PaymentProcessor(CardPaymentStrategy("4111...", "123"))
fun payWithCard() {
viewModelScope.launch {
val result = processor.processPayment(BigDecimal("99.99"))
// Nəticənin işlənməsi
}
}
}
Hilt/Dagger ilə Strategy — Android layihələrində strategiyalar tez-tez DI vasitəsilə inyeksiya edilir. Hilt @Binds və ya @Provides vasitəsilə PaymentStrategy-nin konkret tətbiqini təmin edir. Bu, kontekst kodunu dəyişmədən strategiyanı dəyişməyə imkan verir — müxtəlif kompilyasiya (debug/release) üçün DI modulunu dəyişmək kifayətdir. Məsələn, debug üçün MockPaymentStrategy, release üçün real bank strategiyası inyeksiya edilir. Strategy + DI birləşməsi maksimal çeviklik verir.
Strategy vs State — struktur olaraq nümunələr eynidir: hər ikisi interfeys və konkret siniflərlə kompozisiyadan istifadə edir. Fərq məqsəddədir: Strategy müstəqil alqoritm seçir, State obyektin vəziyyətindən asılı olaraq davranışını idarə edir. State-də kontekst vəziyyət dəyişdikdə strategiyanı özü dəyişir, Strategy-də kontekst keçidi idarə etmir — müştəri alqoritmi açıq şəkildə təyin edir. Strategiyalar bir-biri haqqında bilmir, vəziyyətlər isə bir-birinə keçə bilər.
Strategy vs Command — Command tək bir hərəkəti obyekt kimi inkapsulyasiya edir, Strategy bir-birini əvəz edən alqoritmlər dəstini inkapsulyasiya edir. Command — «nə etməli» (bir execute çağırışı), Strategy — «necə etməli» (bir neçə addımdan ibarət alqoritm). Command növbələr, gecikmiş icra, undo/redo üçün istifadə olunur. Strategy — icra zamanı tapşırığın yerinə yetirilmə üsulunu seçmək üçün. Komandalar strategiyalarla parametrləşdirilərək hər iki nümunəni birləşdirə bilər.
| Xarakteristika | Strategy | State | Command | Template Method |
|---|---|---|---|---|
| Məqsəd | Bir-birini əvəz edən alqoritmlər | Vəziyyətdən asılı davranış | Sorğunun inkapsulyasiyası | Alqoritm skeleti |
| Dəyişmə | Müştəri tərəfindən açıq | Kontekst tərəfindən avtomatik | Müştəri və ya növbə ilə | Varisliklə |
| Səviyyə | Obyekt (kompozisiya) | Obyekt (kompozisiya) | Obyekt | Sinif (varislik) |
Strategy vs Template Method — hər iki nümunə alqoritmləri təyin edir, lakin fərqli üsullarla. Template Method varislikdən istifadə edir: əsas sinif alqoritmin skeletini (şablon metodu) təyin edir, alt siniflər ayrı-ayrı addımları dəyişdirir. Strategy kompozisiyadan istifadə edir: alqoritm tamamilə ayrıca sinfə çıxarılıb. Template Method sabit alqoritm strukturu olan hallar üçün daha sadədir, Strategy — alqoritmlər tamamilə fərqli olduqda və dinamik dəyişə bildikdə.
Ödənişlərin işlənməsi — Strategy-nin klassik nümunəsi. İnternet mağazasının səbəti məhsul siyahısını ehtiva edir, ödəniş üsulu isə istifadəçi tərəfindən seçilir. Hər üsul (kart, PayPal, Apple Pay, Google Pay, kriptovalyuta) — pay(amount) ümumi imzası olan ayrıca strategiyadır. PaymentProcessor konteksti ödənişin necə aparıldığını bilmir — ümumi metodu çağırır. Yeni ödəniş üsulunun əlavə edilməsi səbət kodunun dəyişdirilməsini tələb etmir.
Məlumatların validasiyası — Strategy eyni sahənin müxtəlif validasiya qaydaları üçün tətbiq olunur. EmailValidatorStrategy, PhoneValidatorStrategy, AgeValidatorStrategy validate(input) metodu ilə ümumi ValidationStrategy interfeysini tətbiq edir. Qeydiyyat forması hər sahəni yoxlamaq üçün strategiyalar dəstindən istifadə edir. Validasiya strategiyaları zəncirlə (Chain of Responsibility) birləşdirilə və ya dövrədə hamısı birdən tətbiq edilə bilər. Bu, uzun if-else yoxlamalarını polimorfik validatorlar kolleksiyası ilə əvəz edir.
// Çeşidləmə strategiyası
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) }
}
Autentifikasiya — mobil tətbiqlərdə autentifikasiya strategiyaları provayderdən asılı olaraq dəyişir. login(), logout(), getToken() metodları ilə AuthStrategy EmailPasswordAuth, GoogleAuth, AppleAuth, BiometricAuth üçün tətbiq edilir. AuthManager konteksti strategiyanı DI və ya fabrik vasitəsilə qəbul edir. Bu, giriş ekranını dəyişmədən yeni autentifikasiya provayderləri əlavə etməyə imkan verir. Strategy nümunəsi bir çox OAuth kitabxanaları və Firebase Authentication üçün əsasdır.
Tez-tez verilən suallar
Strategy 3+ alqoritm olduqda və onlar dəyişə və ya genişlənə bildikdə əsaslandırılır. Əgər 2 alqoritm varsa və onlar sabitdirsə — sadə if-else daha az xərclidir. Strategy-dən alqoritmlər tətbiqin müxtəlif hissələrində istifadə edildikdə, alqoritmləri icra zamanı dəyişmək lazım olduqda və ya hər alqoritm öz asılılıqları və testləri tələb etdikdə istifadə edin.
Xeyr, bunlar oxşar strukturlu fərqli nümunələrdir. Strategy — müştəri alqoritmi açıq seçir və strategiyalar müstəqildir. State — obyekt daxili vəziyyət dəyişdikdə öz davranışını dəyişir və vəziyyətlər bir-birinə keçə bilər. State-də kontekst vəziyyət dəyişməsini idarə edir, Strategy-də — müştəri kodu.
Bəli, Swift və Kotlin-də strategiyanı closure və ya lambda kimi ötürmək olar. Swift: typealias PaymentHandler = (Decimal) async throws -> PaymentResult. Kotlin: typealias PaymentFun = suspend (BigDecimal) -> PaymentResult. Bu, sadə hallar üçün kodu sadələşdirir, lakin adlandırma və sənədləşmə itir. 1-2 alqoritm üçün closure kifayətdir, 4+ üçün — ayrıca siniflər daha yaxşıdır.
Hər strategiya mock-asılılıqları ilə ayrıca vahid testlə test edilir. Kontekst mock-strategiya ilə test edilir — kontekstin strategiya metodunu çağırdığı və düzgün parametrləri ötürdüyü yoxlanılır. Swift-də XCTest + protokollar, Kotlin-də MockK və ya Mockito istifadə edin. Əsas üstünlük: hər strategiya mürəkkəb konfiqurasiya olmadan təcrid olunmuş şəkildə test edilir.
Bəli, Strategy (Strategiya) — «Design Patterns: Elements of Reusable Object-Oriented Software» (Gamma, Helm, Johnson, Vlissides, 1994) kitabında təsvir edilmiş 23 nümunədən biridir. Davranış nümunələri qrupuna (Behavioral Patterns) aiddir. Sinonimlər: Policy (Siyasət). Smalltalk-80-də orijinal nümunə kodu GoF-un orijinal nəşrində mövcuddur.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun