Published on

Repository patterni

Authors

10.2 darsda biznes logikasini viewdan view modelga ko'chirdingiz. Endi keyingi qavatga tushamiz: ma'lumot qayerdan keladi?

Hozir view model tarmoq so'rovlari yoki ma'lumot bazasiga bevosita murojaat qilishi mumkin. Bu yana ikkita muammo yaratadi: view model ikki turli ish qilyapti va Preview uchun real tarmoq kerak.

Repository patterni bu ikkala muammoni hal qiladi.

Kutubxonachi metafori: kitob so'raysiz — olasiz. Kutubxonachidan kitob javondan olindimi, boshqa kutubxonadan buyurtma berilganmi yoki raqamli arxivdan olindimi — bilmaysiz. Shunchaki so'radingiz va oldingiz. Repository xuddi shunday ishlaydi.

To'rt qadam

// 1-qadam: Protokol — view model faqat shu bilan gaplashadi
protocol KitobRepository {
    func kitoblarniYukla() async throws -> [Kitob]
    func saqlash(_ kitob: Kitob) async throws
}

// 2-qadam: Haqiqiy implementatsiya — tarmoqdan ma'lumot oladi
struct TarmoqKitobRepository: KitobRepository {
    func kitoblarniYukla() async throws -> [Kitob] {
        let url = URL(string: "https://api.example.com/kitoblar")!
        let (data, _) = try await URLSession.shared.data(from: url)
        return try JSONDecoder().decode([Kitob].self, from: data)
    }

    func saqlash(_ kitob: Kitob) async throws {
        // API ga POST
    }
}

// 3-qadam: Mock implementatsiya — testlar va Preview uchun
struct MockKitobRepository: KitobRepository {
    func kitoblarniYukla() async throws -> [Kitob] {
        // Darhol, bashoratli ma'lumot — tarmoq kerak emas
        [Kitob(sarlavha: "Swift dasturlash"), Kitob(sarlavha: "Dizayn patternlari")]
    }

    func saqlash(_ kitob: Kitob) async throws {
        // Hech narsa — bu soxta
    }
}

// 4-qadam: View modeli — protokolga bog'liq, aniq turga emas
@Observable
class KitobKorinishiModeli {
    var kitoblar: [Kitob] = []
    var yuklanmoqda = false

    // any kalit so'zi — KitobRepository ga mos istalgan turni saqlaydi
    private let repository: any KitobRepository

    // Produksiyada standart haqiqiy, testda mock uzating — bu dependency injection
    init(repository: any KitobRepository = TarmoqKitobRepository()) {
        self.repository = repository
    }

    func kitoblarniYukla() async {
        yuklanmoqda = true
        do {
            kitoblar = try await repository.kitoblarniYukla()
        } catch {
            // Xatoni bu yerda boshqaring
        }
        yuklanmoqda = false
    }
}
QatorVazifasi
protocol KitobRepositoryInterfeys — shartnoma. View modeli faqat shu haqida biladi.
struct TarmoqKitobRepository: KitobRepositoryHaqiqiy implementatsiya — real tarmoq so'rovlari qiladi.
struct MockKitobRepository: KitobRepositoryTest va Preview implementatsiyasi — darhol, hardcoded ma'lumot qaytaradi.
private let repository: any KitobRepositoryanyKitobRepository ga mos istalgan turni saqlaydi. View modeli qaysi biri muhim emas.
init(repository: any KitobRepository = TarmoqKitobRepository())Produksiyada hech narsa uzatmang. Test uchun mock uzating.

Repository variantlari

// Lokal saqlash repository — xuddi shu pattern, boshqa ma'lumot manbasi
struct LocalKitobRepository: KitobRepository {
    let modelContext: ModelContext

    func kitoblarniYukla() async throws -> [Kitob] {
        let tavsif = FetchDescriptor<Kitob>()
        return try modelContext.fetch(tavsif)
    }

    func saqlash(_ kitob: Kitob) async throws {
        modelContext.insert(kitob)
        try modelContext.save()
    }
}
// View modeli o'zgarmaydi — faqat repository o'zgaradi
// Preview da mock inject qilish
#Preview {
    // Mock — tarmoq yo'q, kutish yo'q, bashoratli ma'lumot
    let model = KitobKorinishiModeli(repository: MockKitobRepository())
    KitobRo'yxatiKorinishi(model: model)
}
// Xato holatini test qilish — haqiqiy muvaffaqiyatsiz server kerak emas
struct MuvaffaqiyatsizKitobRepository: KitobRepository {
    func kitoblarniYukla() async throws -> [Kitob] {
        throw URLError(.notConnectedToInternet)
    }
    func saqlash(_ kitob: Kitob) async throws { }
}

#Preview("Xato holati") {
    KitobRo'yxatiKorinishi(model: KitobKorinishiModeli(repository: MuvaffaqiyatsizKitobRepository()))
}

Tezkor ma'lumotnoma

SintaksisVazifasi
protocol Repo { func yukla() async throws -> [T] }Repository interfeysi — barcha implementatsiyalar bajarishi kerak
struct HaqiqiyRepo: Repo { }Produksiya implementatsiyasi — haqiqiy ma'lumot manbasiga gaplashadi
struct MockRepo: Repo { }Test/Preview implementatsiyasi — tezkor, hardcoded ma'lumot
private let repo: any RepoProtokolga mos istalgan turni saqlaydi
init(repo: any Repo = HaqiqiyRepo())Produksiyada standart — test uchun mock uzating

🎯 Topshiriq: repository qo'shish

10.2 darsdan VazifaKorinishiModeli ni oling. Hozir u vazifalar massivini to'g'ridan-to'g'ri saqlaydi. VazifaRepository protokolini vazifalarniYukla() va vazifaQoshish(_ matn: String) metodlari bilan yarating. LocalVazifaRepository — xotira massivi bilan va MockVazifaRepository — uchta hardcoded vazifa bilan yozing. View modelini any VazifaRepository ga bog'lang. Preview Mock bilan ishlashini tasdiqlang.

Buy mea coffee