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 KitobRepositoryany β€” KitobRepository 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