# 03. Creational: Factory Method va Abstract Factory

> "Yangi mahsulot turi (masalan, yangi to'lov tizimi yoki yangi UI kartochkasi) qo'shilganda, agar siz mavjud 10 ta fayldagi `switch-case` kodlarini ochib o'zgartirishga majbur bo'layotgan bo'lsangiz — siz Open/Closed tamoyilini buzdingiz. Factory aynan shu muammoni ildizi bilan yo'q qiladi."

---

## 1. Factory Method vs Abstract Factory: Asosiy Farq Nima?

Ko'p dasturchilar bu ikki patternni aralashtirib yuborishadi. Oddiy qoida:
* **Factory Method:** Faqat **bitta** mahsulotni yaratishga mas'ul (masalan: `createPaymentGateway() -> PaymentGateway`).
* **Abstract Factory:** Bir-biriga mantiqan bog'liq bo'lgan **butun mahsulotlar oilasini** yaratishga mas'ul (masalan: `createButton()`, `createAlert()`, `createTextField()`).

```mermaid
graph TD
    subgraph FM["1. Factory Method (1 ta mahsulot)"]
        direction TB
        FMethod["PaymentFactory.create(type)"] --> Gateway["Bitta Gateway qaytadi\n(Payme, Click yoki ApplePay)"]
    end

    subgraph AF["2. Abstract Factory (Mahsulotlar Oilasi)"]
        direction TB
        AFactory["UIThemeFactory (Interfeys)"]
        AFactory --> DarkF["DarkThemeFactory"]
        AFactory --> LightF["LightThemeFactory"]
        
        DarkF --> DarkBtn["Dark Button"]
        DarkF --> DarkAlert["Dark Alert"]
        DarkF --> DarkField["Dark TextField"]

        LightF --> LightBtn["Light Button"]
        LightF --> LightAlert["Light Alert"]
        LightF --> LightField["Light TextField"]
    end

    style FM fill:#131720,stroke:#7da2ce,stroke-width:1px
    style AF fill:#131720,stroke:#bef264,stroke-width:2px
```

---

## 2. Factory Method: Real FinTech To'lov Tizimi Misoli

Tasavvur qiling, ilovangizda Payme, Click va Apple Pay orqali to'lov mavjud.

### Nega oddiy `switch-case` xato?
```swift
// ❌ OCP ni buzuvchi yondashuv:
func pay(type: String, amount: Double) {
    switch type {
    case "payme": PaymeSDK.charge(...)
    case "click": ClickSDK.charge(...)
    // Yangi 'uzum' qo'shilsa, bu kodni ochib o'zgartirish shart!
    }
}
```

### To'g'ri Factory Method Yechimi:

```swift
// 1. Umumiy Mahsulot Protokoli
public protocol PaymentGateway: Sendable {
    func processPayment(amount: Double) async throws -> String
}

// 2. Aniq Mahsulotlar (Concrete Products)
public final class PaymeGateway: PaymentGateway {
    public func processPayment(amount: Double) async throws -> String {
        return "Payme orqali \(amount) so'm to'landi. Tranzaksiya: #PAY_102"
    }
}

public final class ClickGateway: PaymentGateway {
    public func processPayment(amount: Double) async throws -> String {
        return "Click orqali \(amount) so'm to'landi. Tranzaksiya: #CLK_904"
    }
}

public final class ApplePayGateway: PaymentGateway {
    public func processPayment(amount: Double) async throws -> String {
        return "Apple Pay orqali \(amount) so'm to'landi. Tranzaksiya: #APL_551"
    }
}

// 3. Factory Method
public enum PaymentMethodType {
    case payme
    case click
    case applePay
}

public struct PaymentGatewayFactory {
    public static func makeGateway(for type: PaymentMethodType) -> any PaymentGateway {
        switch type {
        case .payme:
            return PaymeGateway()
        case .click:
            return ClickGateway()
        case .applePay:
            return ApplePayGateway()
        }
    }
}
```

Endi ViewModel faqat `PaymentGateway` protokoli bilan ishlaydi. U Payme yoki Click qanday ishlashini bilishga majbur emas!

---

## 3. Abstract Factory: Multi-Brand & Multi-Theme UI Dvigateli

Bir xil ilovani 2 xil brend (masalan, Oq brend va Qora VIP brend) yoki iOS va macOS uchun chiqarmoqchisiz:

```mermaid
classDiagram
    class UIComponentFactory {
        <<interface>>
        +createButton() View
        +createCard() View
        +createBadge() View
    }

    class StandardThemeFactory {
        +createButton() StandardButton
        +createCard() StandardCard
        +createBadge() StandardBadge
    }

    class VIPGoldThemeFactory {
        +createButton() GoldButton
        +createCard() GoldCard
        +createBadge() GoldBadge
    }

    UIComponentFactory <|.. StandardThemeFactory
    UIComponentFactory <|.. VIPGoldThemeFactory
```

### Swift 6 Implementatsiyasi:
```swift
import SwiftUI

// 1. Mahsulotlar protokollari
public protocol ThemedButton: View {}
public protocol ThemedCard: View {}

// 2. Abstrakt Fabrika Protokoli (Butun oilani birlashtiradi)
public protocol AppThemeFactory {
    associatedtype ButtonView: ThemedButton
    associatedtype CardView: ThemedCard
    
    func makeButton(title: String, action: @escaping () -> Void) -> ButtonView
    func makeCard(title: String, subtitle: String) -> CardView
}

// 3. Aniq Fabrika #1: Standart Mavzu
public struct StandardThemeFactory: AppThemeFactory {
    public func makeButton(title: String, action: @escaping () -> Void) -> some ThemedButton {
        StandardButtonImpl(title: title, action: action)
    }
    
    public func makeCard(title: String, subtitle: String) -> some ThemedCard {
        StandardCardImpl(title: title, subtitle: subtitle)
    }
}

// 4. Aniq Fabrika #2: VIP Oltin Mavzu
public struct VIPGoldThemeFactory: AppThemeFactory {
    public func makeButton(title: String, action: @escaping () -> Void) -> some ThemedButton {
        GoldButtonImpl(title: title, action: action)
    }
    
    public func makeCard(title: String, subtitle: String) -> some ThemedCard {
        GoldCardImpl(title: title, subtitle: subtitle)
    }
}

// Komponentlarning aniq SwiftUI ko'rinishlari
private struct StandardButtonImpl: ThemedButton {
    let title: String
    let action: () -> Void
    var body: some View {
        Button(title, action: action)
            .buttonStyle(.borderedProminent)
            .tint(.blue)
    }
}

private struct GoldButtonImpl: ThemedButton {
    let title: String
    let action: () -> Void
    var body: some View {
        Button(title, action: action)
            .buttonStyle(.borderedProminent)
            .tint(.yellow)
            .foregroundColor(.black)
    }
}

private struct StandardCardImpl: ThemedCard {
    let title: String
    let subtitle: String
    var body: some View {
        VStack { Text(title); Text(subtitle) }.padding().background(Color.gray.opacity(0.1))
    }
}

private struct GoldCardImpl: ThemedCard {
    let title: String
    let subtitle: String
    var body: some View {
        VStack { Text(title); Text(subtitle) }.padding().background(Color.yellow.opacity(0.2))
    }
}
```

---

## 4. Qachon Qaysi Biri Ishlatiladi?

| Mezon | Factory Method | Abstract Factory |
| :--- | :--- | :--- |
| **Yaratiladigan Obyektlar Soni** | 1 ta alohida obyekt | Bir-biriga bog'liq bir nechta obyektlar oilasi |
| **Murakkablik Darajasi** | Past va tushunarli | O'rtacha/Yuqori (ko'plab protokollar talab etiladi) |
| **Qo'llash Joyi** | Parserlar, To'lov tizimlari, Network Clientlar | Multi-Brand tizimlar, Dizayn Tizimlari, Platformlararo UI |

---

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

<details>
<summary><b>1-Savol: Nega Factory patterni Open/Closed (SOLID O) tamoyilini eng zo'r himoya qiluvchi pattern hisoblanadi?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Chunki ilovaning biznes logikasi (masalan, Savat yoki To'lov ViewModel'i) aniq sinflar (`PaymeGateway`, `ClickGateway`) ga emas, umumiy `PaymentGateway` protokoliga bog'langan bo'ladi. Yangi to'lov turi (masalan, `UzumPay`) qo'shilganda mavjud ViewModel'larning birorta satr kodiga tegilmaydi! Faqat yangi `UzumPayGateway` sinfi yoziladi va fabrikaga qo'shiladi. Kod o'zgarishlarga yopiq, kengayishga ochiq bo'ladi.
</details>

<details>
<summary><b>2-Savol: Swift'da Dependency Injection Container va Factory o'rtasida qanday farq bor?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Factory odatda berilgan parametrlar (`type`, `config`) asosida **har safar yangi instancelar** yaratib berishga xizmat qiladi. DI Container esa barcha ilova xizmatlarining (Singletons, Transient, Scoped xizmatlar) hayot siklini boshqaruvchi markazlashgan registrator hisoblanadi. Ko'p hollarda DI Container o'z ichida Factory patternidan foydalanadi.
</details>

---

## 6. Amaliy Topshiriq (Senior Challenge)

Ilovangiz uchun `DocumentExporterFactory` yarating:
1. `PDFExporter`, `CSVExporter` va `JSONExporter` sinflari bitta `DocumentExporting` protokolini tasdiqlasin.
2. `makeExporter(for format: ExportFormat)` orqali kerakli formatga o'tkazuvchi Factory Method yozing.
3. Foydalanuvchi ma'lumotlarini 3 xil formatda eksport qilishni simulyatsiya qilib ko'ring!
