# 09. Behavioral: Strategy va Command Pattern

> "Agar siz har xil to'lov usuli yoki saralash algoritmi uchun butun klass ichini 20 ta `if-else` bilan to'ldirib tashlasangiz — bu Strategy patterniga muhtojlik belgisidir. Agar sizga 'Bekor qilish' (Undo) yoki so'rovlarni navbatga terish kerak bo'lsa — Command sizning najotingizdir."

---

## 1. Strategy Pattern: Algoritmlarni Erkin Almashtirish

**Strategy (Strategiya)** — bu bir xil vazifani bajaruvchi algoritmlar oilasini yaratish, ularning har birini alohida sinfga o'rash va ularni dastur ishlashi davomida (Runtime) bir-birining o'rniga erkin almashtirish imkonini beruvchi pattern.

```mermaid
graph TD
    Client["CheckoutController / Kontekst"] --> Strategy["Interfeys: PaymentStrategy"]
    
    Strategy -.-> S1["PaymeStrategy\n(O'zbekiston ichki kartalari)"]
    Strategy -.-> S2["ClickStrategy\n(USSD va Karta)"]
    Strategy -.-> S3["ApplePayStrategy\n(Biometrika orqali xalqaro)"]
    Strategy -.-> S4["InstallmentStrategy\n(12 oyga bo'lib to'lash)"]

    style Client fill:#131720,stroke:#bef264,stroke-width:2px
    style Strategy fill:#181d26,stroke:#7da2ce,stroke-width:2px
```

### Swift 6 Real Kodi: To'lov Strategiyalari

```swift
import Foundation

// 1. Strategiya Protokoli
public protocol PaymentStrategy: Sendable {
    func pay(amount: Double) async throws -> String
}

// 2. Aniq Strategiyalar
public struct PaymeStrategy: PaymentStrategy {
    public func pay(amount: Double) async throws -> String {
        return "Payme orqali \(amount) so'm to'landi"
    }
}

public struct ClickStrategy: PaymentStrategy {
    public func pay(amount: Double) async throws -> String {
        return "Click orqali \(amount) so'm to'landi"
    }
}

public struct ApplePayStrategy: PaymentStrategy {
    public func pay(amount: Double) async throws -> String {
        return "Apple Pay orqali \(amount) so'm to'landi"
    }
}

// 3. Kontekst (Context)
@MainActor
public final class CheckoutContext {
    private var strategy: any PaymentStrategy
    
    public init(strategy: any PaymentStrategy) {
        self.strategy = strategy
    }
    
    public func setStrategy(_ newStrategy: any PaymentStrategy) {
        self.strategy = newStrategy
    }
    
    public func completeCheckout(amount: Double) async throws -> String {
        return try await strategy.pay(amount: amount)
    }
}
```

Foydalanuvchi ekranda to'lov usulini o'zgartirishi bilan:
`context.setStrategy(ApplePayStrategy())` chaqiriladi. Kodda birorta ham `if-else` yo'q!

---

## 2. Command Pattern: "Bekor Qilish" (Undo/Redo) va So'rovlar Navbati

**Command (Buyruq)** — bu so'rov yoki harakatni (Action) o'z parametrlari bilan birga **alohida mustaqil obyekt** ko'rinishida saqlash imkonini beruvchi pattern.

```mermaid
sequenceDiagram
    autonumber
    participant User as Foydalanuvchi
    participant Manager as CommandHistoryManager
    participant Cmd as TransferMoneyCommand

    User->>Manager: "100,000 so'm o'tkazish" (execute)
    Manager->>Cmd: execute()
    Cmd-->>Manager: Muvaffaqiyatli! Tarixga yozildi.
    
    User->>Manager: "Adashdim, bekor qil!" (Undo tugmasi)
    Manager->>Cmd: undo()
    Cmd-->>User: Pul qaytarildi va balans tiklandi!
```

---

## 3. Real Swift 6 Kodi: Matn Muharriri Uchun Undo/Redo

```swift
import Foundation

// 1. Buyruq Protokoli
public protocol Command {
    func execute()
    func undo()
}

// 2. Qabul Qiluvchi (Receiver - haqiqiy ishni bajaruvchi)
public final class CanvasDocument {
    public var text: String = ""
    
    public func appendText(_ newText: String) {
        text += newText
    }
    
    public func removeLast(count: Int) {
        text = String(text.dropLast(count))
    }
}

// 3. Aniq Buyruq
public final class AppendTextCommand: Command {
    private let document: CanvasDocument
    private let textToAppend: String
    
    public init(document: CanvasDocument, textToAppend: String) {
        self.document = document
        self.textToAppend = textToAppend
    }
    
    public func execute() {
        document.appendText(textToAppend)
    }
    
    public func undo() {
        document.removeLast(count: textToAppend.count)
    }
}

// 4. Tarix Boshqaruvchisi (Invoker)
public final class CommandInvoker {
    private var undoStack: [any Command] = []
    private var redoStack: [any Command] = []
    
    public func executeCommand(_ command: any Command) {
        command.execute()
        undoStack.append(command)
        redoStack.removeAll() // Yangi buyruq kelganda redo tozalanadi
    }
    
    public func undo() {
        guard let command = undoStack.popLast() else { return }
        command.undo()
        redoStack.append(command)
    }
    
    public func redo() {
        guard let command = redoStack.popLast() else { return }
        command.execute()
        undoStack.append(command)
    }
}
```

---

## 4. Offline Request Queue (Internet Yo'qligida Saqlab Qolish)

Mobil ilovalarda Command patternining eng katta qo'llanilish sohasi — bu **Offline Transaction Queue** dir:
1. Foydalanuvchi metroda (internet yo'q) xabar yozadi yoki do'kondan narsa xarid qiladi.
2. Ilova darhol xatolik bermaydi, balki harakatni `SendMessageCommand(message)` sifatida diskka yozib qo'yadi.
3. Internet paydo bo'lishi bilan navbatdagi barcha buyruqlar avtomatik `execute()` qilinadi!

---

## 5. Interaktiv Savol-Javob (Self-Check Quiz)

<details>
<summary><b>1-Savol: Strategy va State patternlari tuzilishi jihatidan deyarli bir xil. Ularning tub farqi nimada?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
* **Strategy patternida** chaqiruvchi (Client) qaysi strategiyani ishlatishni odatda o'zi tanlaydi (masalan, foydalanuvchi Payme tugmasini bosdi). Strategiyalar bir-biridan mustaqil bo'ladi.
* **State patternida** esa holatlar (States) ichki voqealar natijasida **o'z-o'zidan biridan ikkinchisiga o'tib boradi** (masalan, Audio Player: `Playing` -> qo'shiq tugadi -> avtomatik ravishda `Idle` holatiga o'tadi).
</details>

<details>
<summary><b>2-Savol: Command patternida xotira cheksiz to'lib ketmasligi uchun nima qilish kerak?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
`undoStack` hajmiga qat'iy cheklov (masalan, maksimal 50 ta oxirgi buyruq) qo'yilishi lozim (`Ring Buffer` yoki cheklangan massiv). 50 tadan oshganda eng birinchi eski buyruq xotiradan o'chirib tashlanadi.
</details>

---

## 6. Amaliy Topshiriq (Senior Challenge)

`CartOperationCommand` tizimini yarating:
* Foydalanuvchi savatga mahsulot qo'shishi (`AddProductCommand`), mahsulotni o'chirishi (`RemoveProductCommand`) va narxini o'zgartirishi mumkin bo'lsin.
* Har bir amalni "Bekor qilish" (Undo) va "Qaytarish" (Redo) qilish imkonini beruvchi boshqaruvchini test qiling!
