Repository Pattern: ما هو، نمط تجريد البيانات في iOS و Android

المؤلف: IT Sectr نُشر: 2026-02-17 وقت القراءة: 7 دق

Repository Pattern — نمط يضيف طبقة تجريد بين منطق الأعمال ومصادر البيانات. بدلاً من استدعاء API أو قاعدة البيانات أو التخزين المؤقت مباشرة، يوفر Repository واجهة موحدة للحصول على البيانات وتخزينها. هذا يبسط الاختبار والتبديل بين المصادر. اقرأ المزيد في توثيق Android Data Layer.

النقاط الرئيسية

  • Repository Pattern — طبقة بين منطق الأعمال ومصادر البيانات (API، قاعدة بيانات، تخزين مؤقت)
  • DataSource — فئات منفصلة لكل مصدر: RemoteDataSource، LocalDataSource
  • مصدر واحد للحقيقة — يصبح Repository المصدر الوحيد للبيانات لطبقة واجهة المستخدم
  • الاختبار — يمكن استبدال Repository بسهولة بكائن وهمي عبر DI لاختبارات الوحدة
  • التوافق — يعمل مع MVVM و Clean Architecture والأنماط المعمارية الأخرى

ما هو Repository Pattern في تطوير التطبيقات المحمولة؟

Repository Pattern هو نمط هيكلي يعزل منطق الأعمال عن الوصول المباشر إلى مصادر البيانات. بدلاً من أن تقوم Activity أو UIViewController أو ViewModel باستدعاء Retrofit أو URLSession أو Room أو CoreData مباشرة، فإنها تتواصل مع Repository. يقرر Repository من أين يحصل على البيانات — من الشبكة أو قاعدة البيانات أو التخزين المؤقت — ويعيد النتيجة بتنسيق موحد. هذا يطبق مبدأ المسؤولية الفردية — واجهة المستخدم لا تعرف كيف أو من أين تم الحصول على البيانات.

مكونات Repository تتضمن واجهة (بروتوكول)، وتنفيذ، وواحد أو أكثر من DataSources. DataSource هو فئة تعمل مع مصدر واحد: RemoteDataSource يستدعي API عبر عميل HTTP، LocalDataSource يقرأ ويكتب في قاعدة البيانات. يستقبل Repository DataSources عبر المنشئ (حقن التبعيات) ويقرر أي مصدر يستخدم. على سبيل المثال، عند طلب قائمة المستخدمين، يتحقق Repository أولاً من التخزين المؤقت، ثم قاعدة البيانات، ثم الشبكة.

فوائد Repository Pattern: عزل تغييرات مصادر البيانات (تغييرات API، ترحيل قاعدة البيانات) لا تؤثر على طبقة واجهة المستخدم؛ اختبار الوحدة عبر استبدال Repository أو DataSource؛ التخزين المؤقت شفاف لواجهة المستخدم؛ التبديل بين الأوضاع المتصلة وغير المتصلة دون تغيير منطق الشاشة. يوصي مجتمع Android باستخدام Repository كطبقة إلزامية في Clean Architecture.

Repository Pattern في iOS باستخدام Swift: التنفيذ والمثال

تنفيذ iOS لـ Repository مبني على بروتوكولات Swift. يعلن بروتوكول Repository عن طرق الحصول على البيانات وتخزينها. يتم حقن التنفيذ الفعلي عبر المُهيئ — هذا يسمح باستبدال التنفيذ في الاختبارات ومعاينات SwiftUI. يتم أيضًا تعريف DataSources كبروتوكولات: Protocol RemoteDataSource، Protocol LocalDataSource. ViewModel أو Interactor لا يعرف تنفيذًا محددًا — فقط بروتوكول Repository.

swift
protocol UserRepository {
    func getUsers() async throws -> [User]
}

protocol UserRemoteDataSource {
    func fetchUsers() async throws -> [User]
}

protocol UserLocalDataSource {
    func getCachedUsers() throws -> [User]
    func saveUsers(_: [User]) throws
}

final class UserRepositoryImpl: UserRepository {
    private let remote: UserRemoteDataSource
    private let local: UserLocalDataSource

    init(remote: UserRemoteDataSource, local: UserLocalDataSource) {
        self.remote = remote
        self.local = local
    }

    func getUsers() async throws -> [User] {
        if let cached = try? local.getCachedUsers() {
            return cached
        }
        let users = try await remote.fetchUsers()
        try local.saveUsers(users)
        return users
    }
}

حقن التبعيات في iOS لـ Repository يتم تكوينه عادةً عبر مصنع أو حاوية DI (Swinject، Factory). في الاختبارات، يتم استبدال بروتوكول UserRepository بتنفيذ وهمي يعيد بيانات محددة مسبقًا. Async-await يجعل الكود متزامنًا وقابلاً للقراءة بدون closures و delegates. للتفاعل مع Combine، تعيد طرق Repository AnyPublisher بدلاً من async throws.

Repository Pattern في Android باستخدام Kotlin: مثال مع Flow

تنفيذ Android لـ Repository يستخدم على نطاق واسع Kotlin Coroutines و Flow للعمليات غير المتزامنة. توصي Google باستخدام Repository في الدليل الرسمي لهندسة Android (Android Architecture Components). يقبل Repository RemoteDataSource (Retrofit) و LocalDataSource (Room) عبر المنشئ، وتشترك ViewModel في Flow من Repository. يدير Repository استراتيجية البيانات: التخزين المؤقت أولاً، الشبكة أولاً، أو دائمًا الشبكة مع الكتابة في التخزين المؤقت.

kotlin
interface UserRepository {
    fun getUsers(): Flow<Result<List<User>>>
}

interface UserRemoteDataSource {
    suspend fun fetchUsers(): List<User>
}

interface UserLocalDataSource {
    fun getCachedUsers(): Flow<List<User>>
    suspend fun saveUsers(users: List<User>)
}

class UserRepositoryImpl(
    private val remote: UserRemoteDataSource,
    private val local: UserLocalDataSource
) : UserRepository {

    override fun getUsers(): Flow<Result<List<User>>> = flow {
        emit(Result.Loading)
        local.getCachedUsers().collect { cached ->
            if (cached.isNotEmpty()) {
                emit(Result.Success(cached))
            }
        }
        try {
            val users = remote.fetchUsers()
            local.saveUsers(users)
            emit(Result.Success(users))
        } catch (e: Exception) {
            emit(Result.Error(e))
        }
    }
}

غلاف Result في المثال أعلاه هو المعيار لـ Android: فئة مختومة Result تُعلم ViewModel بحالة التحميل (تحميل، نجاح، خطأ). تشترك ViewModel عبر collect وتُحدّث StateFlow أو LiveData. Repository مع Flow يُعلم واجهة المستخدم تلقائيًا بالتغييرات في قاعدة البيانات — هذا فرق رئيسي عن الطلبات لمرة واحدة حيث لا تعرف واجهة المستخدم بالتغييرات دون تحديث يدوي.

DataSource: Remote، Local والتخزين المؤقت للبيانات

DataSource — فئات مسؤولة عن العمل مع مصدر بيانات محدد. يستخدم RemoteDataSource عميل HTTP (URLSession، Retrofit، Ktor) للحصول على البيانات من API. يعمل LocalDataSource مع التخزين المحلي (CoreData، Realm، Room، UserDefaults، DataStore). لكل DataSource مسؤولية محدودة: RemoteDataSource يعرف فقط تنسيق طلب API، LocalDataSource — مخطط قاعدة البيانات. يجمع Repository بينهما، مطبقًا استراتيجية التخزين المؤقت.

DataSourceمنصة iOSمنصة Androidالمصدر
RemoteURLSession + CodableRetrofit + Moshi/GsonAPI REST / GraphQL
Local (قاعدة بيانات)CoreData, SwiftDataRoom, SQLDelightSQLite على الجهاز
Local (تخزين مؤقت)NSCache, UserDefaultsDataStore, EncryptedSPفي الذاكرة / القرص
تفضيلاتUserDefaults, KeychainSharedPreferences, EncryptedSPالإعدادات، الرموز المميزة

استراتيجيات التخزين المؤقت في Repository: Cache-First (التخزين المؤقت أولاً، ثم التحميل في الخلفية)، Network-Only (الشبكة فقط، لشاشات الدفع)، Network-First-With-Cache-Backup (الشبكة أولاً، الرجوع إلى التخزين المؤقت عند الخطأ). اختيار الاستراتيجية يعتمد على السيناريو: قائمة الدول يمكن تخزينها مؤقتًا لفترة طويلة، أسعار العملات — لمدة 15 دقيقة، رصيد المحفظة — من الشبكة فقط. ينفذ Repository الاستراتيجية ويغيرها دون تعديل ViewModel أو واجهة المستخدم.

Repository Pattern مقابل Service Layer: الاختلافات والاختيار

Repository و Service هما نمطان مختلفان بوظائف متداخلة. Repository مسؤول عن الوصول إلى البيانات والتخزين المؤقت، ويعيد نماذج البيانات. Service (أو Interactor، Use Case) يحتوي على منطق الأعمال: التحقق، تحويل البيانات، تنسيق استدعاءات متعددة لـ Repository. يمكن لـ Service دمج UserRepository و OrderRepository و NotificationRepository لمعالجة طلب. Repository لا يحتوي على منطق أعمال — فقط CRUD والتخزين المؤقت.

متى تختار Repository — التنقل بين البيانات مع مصادر متعددة (API + قاعدة بيانات + تخزين مؤقت)، بنية offline-first، الحاجة إلى التخزين المؤقت والتبديل الشفاف للمصادر. Repository إلزامي في Clean Architecture وتوصي به Google لتطبيقات Android. في بنية VIPER على iOS، يؤدي دور Repository طبقة Interactor التي تتفاعل مع Manager أو Service للوصول إلى البيانات.

متى يكون Service كافيًا — تطبيقات بسيطة بمصدر بيانات واحد، شاشات للقراءة فقط بدون كتابة، مشاريع بدون وضع عدم الاتصال. في هذه الحالات، يتم استخدام DataSource مباشرة بواسطة ViewModel أو Presenter، ويصبح Repository طبقة زائدة عن الحاجة. ومع ذلك، إضافة Repository في مرحلة مبكرة لا يتطلب جهدًا كبيرًا ويبسط إضافة التخزين المؤقت والاختبارات في المستقبل.

الأسئلة الشائعة

كيف يختلف Repository عن DataSource؟

DataSource هو فئة تعمل مع مصدر واحد (API، قاعدة بيانات، تخزين مؤقت). Repository هو فئة تدير DataSources متعددة وتوفر واجهة موحدة. يقرر Repository أي DataSource يستخدم وينسق التخزين المؤقت. DataSource لا يعرف عن وجود مصادر أخرى؛ Repository لا يعرف تفاصيل تنفيذ كل مصدر.

هل Repository ضروري في iOS مع SwiftUI؟

نعم، Repository مفيد في SwiftUI لفصل البيانات عن View. تشترك ViewModel في Publisher من Repository، ويدير Repository التخزين المؤقت والمزامنة. في التطبيقات البسيطة، يمكن استخدام URLSession مباشرة في ViewModel، لكن من أجل قابلية الاختبار والتوسع، يُفضل Repository. Apple لا تفرض النمط، لكنه متوافق مع SwiftData و Network.framework.

كيف تختبر Repository مع DataSources متعددة؟

يتم استبدال DataSources بكائنات وهمية عبر حقن التبعيات. ينشئ الاختبار RemoteDataSource وهميًا (يعيد JSON محدد مسبقًا) و LocalDataSource وهميًا (يتحقق من حفظ البيانات). يتم اختبار Repository بشكل معزول: يتم التحقق من استراتيجية التخزين المؤقت، معالجة الأخطاء، والترتيب الصحيح للاستدعاءات. لاختبارات التكامل، يُستخدم TestDispatcher (Kotlin) أو MainActor.run (Swift).

هل يمكن استخدام Repository بدون واجهة (بروتوكول)؟

ممكن لكن غير موصى به. بدون بروتوكول، من المستحيل استبدال التنفيذ في الاختبارات والمعاينات. في Kotlin، تسمح واجهة Repository باستبدال التنفيذ عبر DI (Dagger، Hilt، Koin). في Swift، بروتوكول Repository إلزامي لاختبار كود async-await و Combine. الاستثناء هو المشاريع البسيطة بمصدر بيانات واحد حيث Repository لا يحتوي على منطق تخزين مؤقت.

ما هو offline-first في سياق Repository؟

Offline-first هي استراتيجية حيث يعمل التطبيق بدون إنترنت باستخدام البيانات المحلية. يلعب Repository دورًا رئيسيًا: أولاً يعيد البيانات من DataSource المحلي، ثم يتزامن مع الخادم في الخلفية. يرى المستخدم البيانات فورًا، ويقوم Repository بتحديثها بعد التحميل من الشبكة. Room مع Flow يوفر تحديثات تفاعلية لواجهة المستخدم عند تغيير البيانات في قاعدة البيانات المحلية.

الملخص

  • Repository Pattern — طبقة تجريد بين واجهة المستخدم ومصادر البيانات
  • DataSource — فئات منفصلة لـ API وقاعدة البيانات والتخزين المؤقت
  • البروتوكولات — ضرورية للاختبار واستبدال التنفيذات
  • استراتيجيات التخزين المؤقت — Cache-First، Network-Only، Network-First-With-Cache-Backup
  • iOS — async-await أو Combine مع بروتوكولات
  • Android — Kotlin Flow + Room + Retrofit، نهج موصى به من Google
  • الاختبار — DataSources وهمية عبر DI، التحقق من استراتيجيات التخزين المؤقت

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا