Repository Pattern: τι είναι, πρότυπο αφαίρεσης δεδομένων σε iOS και Android

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-02-17 Χρόνος ανάγνωσης: 7 λεπ

Repository Pattern — ένα πρότυπο που προσθέτει ένα επίπεδο αφαίρεσης μεταξύ της επιχειρηματικής λογικής και των πηγών δεδομένων. Αντί για άμεσες κλήσεις API, βάσης δεδομένων ή προσωρινής μνήμης, το Repository παρέχει μια ενοποιημένη διεπαφή για λήψη και αποθήκευση δεδομένων. Αυτό απλοποιεί τη δοκιμή και την εναλλαγή μεταξύ πηγών. Περισσότερα στην τεκμηρίωση Android Data Layer.

Κύρια σημεία

  • Repository Pattern — ενδιάμεσο επίπεδο μεταξύ επιχειρηματικής λογικής και πηγών δεδομένων (API, ΒΔ, προσωρινή μνήμη)
  • DataSource — ξεχωριστές κλάσεις για κάθε πηγή: RemoteDataSource, LocalDataSource
  • Single source of truth — το Repository γίνεται η ενιαία πηγή δεδομένων για το επίπεδο UI
  • Δοκιμή — το Repository αντικαθίσταται εύκολα με mock αντικείμενο μέσω DI για μοναδιαίες δοκιμές
  • Συμβατότητα — λειτουργεί με MVVM, Clean Architecture και άλλα αρχιτεκτονικά πρότυπα

Τι είναι το Repository Pattern στην ανάπτυξη εφαρμογών για κινητά;

Repository Pattern — ένα δομικό πρότυπο που απομονώνει την επιχειρηματική λογική από την άμεση πρόσβαση σε πηγές δεδομένων. Αντί το Activity, UIViewController ή ViewModel να καλούν απευθείας Retrofit, URLSession, Room ή CoreData, απευθύνονται στο Repository. Το Repository αποφασίζει από πού θα λάβει δεδομένα: από το δίκτυο, τη βάση δεδομένων ή την προσωρινή μνήμη, και επιστρέφει το αποτέλεσμα σε ενοποιημένη μορφή. Αυτή είναι μια υλοποίηση της αρχής της ενιαίας ευθύνης — το UI δεν γνωρίζει πώς και από πού ελήφθησαν τα δεδομένα.

Στοιχεία του Repository περιλαμβάνουν τη διεπαφή (protocol), την υλοποίηση και ένα ή περισσότερα DataSource. DataSource — μια κλάση που εργάζεται με μία πηγή: το RemoteDataSource καλεί API μέσω HTTP πελάτη, το LocalDataSource διαβάζει και γράφει στη βάση δεδομένων. Το Repository λαμβάνει τα DataSource μέσω του κατασκευαστή (Dependency Injection) και επιλέγει σε ποια πηγή να απευθυνθεί. Για παράδειγμα, κατά την αίτηση λίστας χρηστών, το Repository ελέγχει πρώτα την προσωρινή μνήμη, μετά τη βάση δεδομένων, έπειτα το δίκτυο.

Πλεονεκτήματα του Repository Pattern: η απομόνωση αλλαγών στις πηγές δεδομένων (αλλαγή API, μετεγκατάσταση ΒΔ) δεν επηρεάζει το επίπεδο UI; μοναδιαίες δοκιμές μέσω αντικατάστασης του Repository ή DataSource; προσωρινή αποθήκευση διαφανής για το UI; εναλλαγή μεταξύ online και offline λειτουργίας χωρίς αλλαγή της λογικής οθόνης. Η κοινότητα Android συνιστά το Repository ως υποχρεωτικό επίπεδο στην Clean Architecture.

Repository Pattern σε iOS με Swift: υλοποίηση και παράδειγμα

Υλοποίηση iOS του Repository βασίζεται σε πρωτόκολλα Swift. Το πρωτόκολλο Repository δηλώνει μεθόδους λήψης και αποθήκευσης δεδομένων. Η πραγματική υλοποίηση εισάγεται μέσω του αρχικοποιητή — αυτό επιτρέπει την αντικατάσταση της υλοποίησης σε δοκιμές και preview SwiftUI. Τα DataSource δηλώνονται επίσης με πρωτόκολλα: 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
    }
}

Dependency Injection σε iOS για το Repository συνήθως ρυθμίζεται μέσω εργοστασίου ή κοντέινερ DI (Swinject, Factory). Σε δοκιμές, το πρωτόκολλο UserRepository αντικαθίσταται με mock υλοποίηση που επιστρέφει προκαθορισμένα δεδομένα. Το 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: το sealed class Result ενημερώνει το ViewModel για την κατάσταση φόρτωσης (Loading, Success, Error). Το ViewModel εγγράφεται μέσω collect και ενημερώνει το StateFlow ή LiveData. Το Repository με Flow ειδοποιεί αυτόματα το UI για αλλαγές στη βάση δεδομένων — αυτή είναι η βασική διαφορά από ερωτήματα μιας χρήσης όπου το UI δεν μαθαίνει για αλλαγές χωρίς μη αυτόματη ανανέωση.

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/GsonREST / GraphQL API
Local (ΒΔ)CoreData, SwiftDataRoom, SQLDelightSQLite στη συσκευή
Local (προσωρ. μνήμη)NSCache, UserDefaultsDataStore, EncryptedSPΣτη μνήμη / δίσκο
ΠροτίμησηUserDefaults, KeychainSharedPreferences, EncryptedSPΡυθμίσεις, κωδικοί

Στρατηγικές προσωρινής αποθήκευσης στο Repository: Cache-First (πρώτα προσωρινή μνήμη, μετά φόρτωση παρασκηνίου), Network-Only (μόνο δίκτυο, για οθόνες πληρωμής), Network-First-With-Cache-Backup (πρώτα δίκτυο, σε σφάλμα — προσωρινή μνήμη). Η επιλογή στρατηγικής εξαρτάται από το σενάριο: η λίστα χωρών μπορεί να αποθηκευτεί προσωρινά για μεγάλο διάστημα, οι συναλλαγματικές ισοτιμίες — 15 λεπτά, το υπόλοιπο πορτοφολιού — μόνο από το δίκτυο. Το Repository υλοποιεί τη στρατηγική και την αλλάζει χωρίς τροποποίηση του ViewModel ή UI.

Repository Pattern vs 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 — απλές εφαρμογές με μία πηγή δεδομένων, οθόνες μόνο για ανάγνωση χωρίς εγγραφή, έργα χωρίς λειτουργία offline. Σε τέτοιες περιπτώσεις, το DataSource χρησιμοποιείται απευθείας από το ViewModel ή Presenter, και το Repository γίνεται περιττό επίπεδο. Ωστόσο, η προσθήκη Repository σε πρώιμο στάδιο δεν απαιτεί μεγάλο κόστος και διευκολύνει την προσθήκη προσωρινής αποθήκευσης και δοκιμών στο μέλλον.

Συχνές Ερωτήσεις

Σε τι διαφέρει το Repository από το DataSource;

DataSource — μια κλάση που εργάζεται με μία πηγή (API, ΒΔ, προσωρινή μνήμη). Repository — μια κλάση που διαχειρίζεται πολλαπλά DataSource και παρέχει μια ενοποιημένη διεπαφή. Το Repository αποφασίζει από ποιο DataSource θα λάβει δεδομένα και συντονίζει την προσωρινή αποθήκευση. Το DataSource δεν γνωρίζει την ύπαρξη άλλων πηγών, το Repository δεν γνωρίζει λεπτομέρειες υλοποίησης κάθε πηγής.

Χρειάζεται Repository σε iOS με SwiftUI;

Ναι, το Repository είναι χρήσιμο στο SwiftUI για τον διαχωρισμό δεδομένων από το View. Το ViewModel εγγράφεται στο Publisher από το Repository, και το Repository διαχειρίζεται την προσωρινή αποθήκευση και συγχρονισμό. Σε απλές εφαρμογές μπορεί να χρησιμοποιηθεί απευθείας URLSession στο ViewModel, αλλά για δοκιμασιμότητα και επεκτασιμότητα το Repository είναι προτιμότερο. Η Apple δεν επιβάλλει αυτό το πρότυπο, αλλά είναι συμβατό με SwiftData και Network.framework.

Πώς δοκιμάζεται το Repository με πολλαπλά DataSource;

Τα DataSource αντικαθίστανται με mock αντικείμενα μέσω Dependency Injection. Η δοκιμή δημιουργεί ένα mock RemoteDataSource (επιστρέφει προκαθορισμένο JSON) και ένα mock LocalDataSource (ελέγχει αν τα δεδομένα αποθηκεύτηκαν). Το Repository δοκιμάζεται απομονωμένα: ελέγχεται η στρατηγική προσωρινής αποθήκευσης, η διαχείριση σφαλμάτων και η σωστή σειρά κλήσεων. Για δοκιμές ολοκλήρωσης χρησιμοποιείται TestDispatcher (Kotlin) ή MainActor.run (Swift).

Μπορεί να χρησιμοποιηθεί Repository χωρίς διεπαφή (protocol);

Μπορεί, αλλά δεν συνιστάται. Χωρίς πρωτόκολλο είναι αδύνατη η αντικατάσταση υλοποίησης σε δοκιμές και preview. Στην Kotlin, η διεπαφή Repository επιτρέπει την αντικατάσταση υλοποίησης μέσω DI (Dagger, Hilt, Koin). Στη Swift, το πρωτόκολλο Repository είναι υποχρεωτικό για τη δοκιμή κώδικα async-await και Combine. Εξαίρεση — απλά έργα με μία πηγή δεδομένων, όπου το Repository δεν περιέχει λογική προσωρινής αποθήκευσης.

Τι είναι το offline-first στο πλαίσιο του Repository;

Offline-first — μια στρατηγική όπου η εφαρμογή λειτουργεί χωρίς διαδίκτυο χρησιμοποιώντας τοπικά δεδομένα. Το Repository παίζει βασικό ρόλο: πρώτα επιστρέφει δεδομένα από το τοπικό DataSource, στη συνέχεια συγχρονίζεται με τον διακομιστή στο παρασκήνιο. Ο χρήστης βλέπει τα δεδομένα άμεσα και το Repository τα ενημερώνει μετά τη φόρτωση από το δίκτυο. Το Room με Flow παρέχει αντιδραστική ενημέρωση του UI κατά την αλλαγή δεδομένων στην τοπική βάση.

Σύνοψη

  • Repository Pattern — επίπεδο αφαίρεσης μεταξύ UI και πηγών δεδομένων
  • DataSource — ξεχωριστές κλάσεις για API, ΒΔ και προσωρινή μνήμη
  • Πρωτόκολλα — υποχρεωτικά για δοκιμή και αντικατάσταση υλοποιήσεων
  • Στρατηγικές προσωρινής αποθήκευσης — Cache-First, Network-Only, Network-First-With-Cache-Backup
  • iOS — async-await ή Combine με πρωτόκολλα
  • Android — Kotlin Flow + Room + Retrofit, προσέγγιση που συνιστά η Google
  • Δοκιμή — mock DataSource μέσω DI, έλεγχος στρατηγικών προσωρινής αποθήκευσης

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης