Repository Pattern: wat is het, patroon voor gegevensabstractie in iOS en Android

Auteur: IT Sectr Gepubliceerd: 2026-02-17 Leestijd: 7 min

Repository Pattern — een patroon dat een abstractielaag toevoegt tussen bedrijfslogica en gegevensbronnen. In plaats van directe aanroepen naar API, database of cache biedt Repository een uniforme interface voor het ophalen en opslaan van gegevens. Dit vereenvoudigt testen en schakelen tussen bronnen. Meer in Android Data Layer-documentatie.

Belangrijkste

  • Repository Pattern — tussenlaag tussen bedrijfslogica en gegevensbronnen (API, DB, cache)
  • DataSource — aparte klassen voor elke bron: RemoteDataSource, LocalDataSource
  • Single source of truth — Repository wordt de enige gegevensbron voor de UI-laag
  • Testen — Repository wordt eenvoudig vervangen door een mock-object via DI voor unittesten
  • Compatibiliteit — werkt met MVVM, Clean Architecture en andere architectuurpatronen

Wat is Repository Pattern in mobiele ontwikkeling?

Repository Pattern — een structuurpatroon dat bedrijfslogica isoleert van directe toegang tot gegevensbronnen. In plaats van dat Activity, UIViewController of ViewModel rechtstreeks Retrofit, URLSession, Room of CoreData aanroepen, wenden ze zich tot Repository. Repository beslist waar gegevens vandaan komen: van het netwerk, de database of de cache, en retourneert het resultaat in een uniform formaat. Dit is een implementatie van het single-responsibility principe — de UI weet niet hoe en waar de gegevens zijn verkregen.

Repository-componenten omvatten een interface (protocol), implementatie en een of meer DataSources. DataSource — een klasse die met één bron werkt: RemoteDataSource roept API aan via een HTTP-client, LocalDataSource leest en schrijft naar de database. Repository ontvangt DataSources via de constructor (Dependency Injection) en kiest welke bron te gebruiken. Bij een verzoek om een gebruikerslijst controleert Repository bijvoorbeeld eerst de cache, dan de database, dan het netwerk.

Voordelen van Repository Pattern: isolatie van wijzigingen in gegevensbronnen (API-wijziging, DB-migratie) heeft geen invloed op de UI-laag; unittesten door Repository of DataSource te vervangen; caching transparant voor de UI; schakelen tussen online en offline modus zonder wijziging van de schermlogica. De Android-gemeenschap beveelt Repository aan als verplichte laag in Clean Architecture.

Repository Pattern in iOS met Swift: implementatie en voorbeeld

iOS-implementatie van Repository is gebaseerd op Swift-protocollen. Het Repository-protocol declareert methoden voor het ophalen en opslaan van gegevens. De daadwerkelijke implementatie wordt geïnjecteerd via de initializer — dit maakt het mogelijk de implementatie te vervangen in tests en SwiftUI-previews. DataSources worden ook gedeclareerd met protocollen: Protocol RemoteDataSource, Protocol LocalDataSource. ViewModel of Interactor kent de concrete implementatie niet — alleen het Repository-protocol.

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 in iOS voor Repository wordt meestal geconfigureerd via een fabriek of DI-container (Swinject, Factory). In tests wordt het UserRepository-protocol vervangen door een mock-implementatie die vooraf gedefinieerde gegevens retourneert. Async-await maakt de code synchroon en leesbaar zonder closures en delegates. Voor Combine-reactiviteit retourneren Repository-methoden AnyPublisher in plaats van async throws.

Repository Pattern in Android met Kotlin: voorbeeld met Flow

Android-implementatie van Repository maakt veelvuldig gebruik van Kotlin Coroutines en Flow voor asynchrone taken. Google beveelt Repository aan in de officiële Android-architectuurgids (Android Architecture Components). Repository ontvangt RemoteDataSource (Retrofit) en LocalDataSource (Room) via de constructor, en ViewModel abonneert zich op Flow van Repository. Repository beheert de gegevensstrategie: eerst cache, dan netwerk of altijd netwerk met wegschrijven naar cache.

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-wrapper in bovenstaand voorbeeld is standaard voor Android: sealed class Result informeert ViewModel over de laadstatus (Loading, Success, Error). ViewModel abonneert zich via collect en werkt StateFlow of LiveData bij. Repository met Flow stelt UI automatisch op de hoogte van wijzigingen in de database — dit is het belangrijkste verschil met eenmalige query's waarbij UI niets van wijzigingen weet zonder handmatige verversing.

DataSource: Remote, Local en gegevenscaching

DataSource — klassen verantwoordelijk voor het werken met een specifieke gegevensbron. RemoteDataSource gebruikt een HTTP-client (URLSession, Retrofit, Ktor) om gegevens van de API op te halen. LocalDataSource werkt met lokale opslag (CoreData, Realm, Room, UserDefaults, DataStore). Elke DataSource heeft een beperkte verantwoordelijkheid: RemoteDataSource kent alleen het API-verzoekformaat, LocalDataSource — het databaseschema. Repository combineert ze en implementeert een cacheringsstrategie.

DataSourceiOS-platformAndroid-platformBron
RemoteURLSession + CodableRetrofit + Moshi/GsonREST / GraphQL API
Local (DB)CoreData, SwiftDataRoom, SQLDelightSQLite op apparaat
Local (cache)NSCache, UserDefaultsDataStore, EncryptedSPIn-memory / schijf
VoorkeurUserDefaults, KeychainSharedPreferences, EncryptedSPInstellingen, tokens

Cacheringsstrategieën in Repository: Cache-First (eerst cache, dan laden op de achtergrond), Network-Only (alleen netwerk, voor betalingsschermen), Network-First-With-Cache-Backup (eerst netwerk, bij fout — cache). De keuze van strategie hangt af van het scenario: landenlijst kan lang worden gecacht, wisselkoersen — 15 minuten, portemonnee-saldo — alleen uit het netwerk. Repository implementeert de strategie en wijzigt deze zonder ViewModel of UI aan te passen.

Repository Pattern vs Service Layer: verschillen en keuze

Repository en Service — verschillende patronen met overlappende functies. Repository is verantwoordelijk voor gegevenstoegang en caching, en retourneert gegevensmodellen. Service (of Interactor, Use Case) bevat bedrijfslogica: validatie, gegevenstransformatie, orkestratie van aanroepen naar meerdere Repositories. Service kan UserRepository, OrderRepository en NotificationRepository combineren voor het verwerken van een bestelling. Repository bevat geen bedrijfslogica — alleen CRUD en caching.

Wanneer Repository kiezen — navigatie door gegevens met meerdere bronnen (API + DB + cache), offline-first architectuur, behoefte aan caching en transparant schakelen tussen bronnen. Repository is verplicht in Clean Architecture en wordt aanbevolen door Google voor Android-applicaties. In VIPER-architectuur op iOS wordt de rol van Repository vervuld door de Interactor-laag, die samenwerkt met Manager of Service voor gegevenstoegang.

Wanneer Service volstaat — eenvoudige applicaties met één gegevensbron, alleen-lezen schermen zonder schrijven, projecten zonder offline-modus. In dergelijke gevallen wordt DataSource direct gebruikt door ViewModel of Presenter, en wordt Repository een overbodige laag. Het toevoegen van Repository in een vroeg stadium vereist echter geen grote kosten en vergemakkelijkt het toevoegen van caching en tests in de toekomst.

Veelgestelde vragen

Wat is het verschil tussen Repository en DataSource?

DataSource — een klasse die met één bron werkt (API, DB, cache). Repository — een klasse die meerdere DataSources beheert en een uniforme interface biedt. Repository beslist uit welke DataSource gegevens moeten worden gehaald en coördineert caching. DataSource weet niet van het bestaan van andere bronnen, Repository kent de implementatiedetails van elke bron niet.

Is Repository nodig in iOS met SwiftUI?

Ja, Repository is nuttig in SwiftUI voor het scheiden van gegevens van View. ViewModel abonneert zich op Publisher van Repository, en Repository beheert caching en synchronisatie. In eenvoudige applicaties kan URLSession direct in ViewModel worden gebruikt, maar voor testbaarheid en schaalbaarheid heeft Repository de voorkeur. Apple legt dit patroon niet op, maar het is compatibel met SwiftData en Network.framework.

Hoe test je Repository met meerdere DataSources?

DataSources worden vervangen door mock-objecten via Dependency Injection. De test maakt een mock RemoteDataSource (retourneert vooraf gedefinieerde JSON) en een mock LocalDataSource (controleert of gegevens zijn opgeslagen). Repository wordt geïsoleerd getest: de cacheringsstrategie, foutafhandeling en juiste aanroepvolgorde worden gecontroleerd. Voor integratietests wordt TestDispatcher (Kotlin) of MainActor.run (Swift) gebruikt.

Kan Repository zonder interface (protocol) worden gebruikt?

Het kan, maar wordt niet aanbevolen. Zonder protocol is het onmogelijk de implementatie te vervangen in tests en previews. In Kotlin maakt de Repository-interface vervanging van de implementatie via DI (Dagger, Hilt, Koin) mogelijk. In Swift is het Repository-protocol verplicht voor het testen van async-await en Combine-code. Uitzondering — eenvoudige projecten met één gegevensbron, waarbij Repository geen cacheringslogica bevat.

Wat is offline-first in de context van Repository?

Offline-first — een strategie waarbij de applicatie zonder internet werkt met behulp van lokale gegevens. Repository speelt een sleutelrol: het retourneert eerst gegevens van de lokale DataSource en synchroniseert vervolgens op de achtergrond met de server. De gebruiker ziet gegevens onmiddellijk en Repository werkt ze bij na het laden van het netwerk. Room met Flow zorgt voor reactieve UI-updates bij wijzigingen in de lokale database.

Samenvatting

  • Repository Pattern — abstractielaag tussen UI en gegevensbronnen
  • DataSource — aparte klassen voor API, DB en cache
  • Protocollen — verplicht voor testen en vervangen van implementaties
  • Cacheringsstrategieën — Cache-First, Network-Only, Network-First-With-Cache-Backup
  • iOS — async-await of Combine met protocollen
  • Android — Kotlin Flow + Room + Retrofit, door Google aanbevolen aanpak
  • Testen — mock DataSource via DI, controle van cacheringsstrategieën

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook