Repository Pattern: o que é, o padrão de abstração de dados em iOS e Android

Autor: IT Sectr Publicado: 2026-02-17 Tempo de leitura: 7 min

Repository Pattern — um padrão que adiciona uma camada de abstração entre a lógica de negócios e as fontes de dados. Em vez de chamar diretamente a API, banco de dados ou cache, o Repository fornece uma interface unificada para obter e armazenar dados. Isso simplifica os testes e a alternância entre fontes. Saiba mais na documentação do Android Data Layer.

Principais pontos

  • Repository Pattern — uma camada entre a lógica de negócios e as fontes de dados (API, BD, cache)
  • DataSource — classes separadas para cada fonte: RemoteDataSource, LocalDataSource
  • Fonte única da verdade — o Repository torna-se a única fonte de dados para a camada de UI
  • Testes — o Repository é facilmente substituído por um objeto mock via DI para testes unitários
  • Compatibilidade — funciona com MVVM, Clean Architecture e outros padrões arquiteturais

O que é o Repository Pattern no desenvolvimento mobile?

Repository Pattern é um padrão estrutural que isola a lógica de negócios do acesso direto às fontes de dados. Em vez de uma Activity, UIViewController ou ViewModel chamar diretamente Retrofit, URLSession, Room ou CoreData, elas se comunicam com o Repository. O Repository decide de onde obter os dados — da rede, banco de dados ou cache — e retorna o resultado em um formato unificado. Isso implementa o princípio da responsabilidade única — a UI não sabe como ou de onde os dados foram obtidos.

Componentes do Repository incluem uma interface (protocolo), uma implementação e um ou mais DataSources. Um DataSource é uma classe que trabalha com uma única fonte: RemoteDataSource chama a API através de um cliente HTTP, LocalDataSource lê e escreve no banco de dados. O Repository recebe os DataSources através do construtor (Injeção de Dependência) e decide qual fonte usar. Por exemplo, ao solicitar uma lista de usuários, o Repository primeiro verifica o cache, depois o banco de dados, depois a rede.

Benefícios do Repository Pattern: isolamento de mudanças nas fontes de dados (alterações de API, migrações de BD) não afeta a camada de UI; testes unitários através da substituição do Repository ou DataSource; cache transparente para a UI; alternância entre modos online e offline sem alterar a lógica da tela. A comunidade Android recomenda o Repository como camada obrigatória na Clean Architecture.

Repository Pattern em iOS com Swift: implementação e exemplo

Implementação iOS do Repository é construída em protocolos Swift. O protocolo Repository declara métodos para obter e armazenar dados. A implementação real é injetada através do inicializador — isso permite substituir a implementação em testes e previews do SwiftUI. DataSources também são declarados como protocolos: Protocol RemoteDataSource, Protocol LocalDataSource. A ViewModel ou Interactor não conhece uma implementação específica — apenas o protocolo 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
    }
}

Injeção de Dependência em iOS para Repository é tipicamente configurada através de uma fábrica ou contêiner DI (Swinject, Factory). Em testes, o protocolo UserRepository é substituído por uma implementação mock que retorna dados predefinidos. Async-await torna o código síncrono e legível sem closures e delegates. Para reatividade com Combine, os métodos do Repository retornam AnyPublisher em vez de async throws.

Repository Pattern em Android com Kotlin: exemplo com Flow

Implementação Android do Repository usa extensivamente Kotlin Coroutines e Flow para operações assíncronas. O Google recomenda o Repository no guia oficial de arquitetura Android (Android Architecture Components). O Repository aceita RemoteDataSource (Retrofit) e LocalDataSource (Room) através do construtor, e a ViewModel assina um Flow do Repository. O Repository gerencia a estratégia de dados: cache primeiro, rede primeiro, ou sempre rede com escrita em 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))
        }
    }
}

Wrapper Result no exemplo acima é padrão para Android: uma classe selada Result informa a ViewModel sobre o estado de carregamento (Loading, Success, Error). A ViewModel assina via collect e atualiza StateFlow ou LiveData. Repository com Flow notifica automaticamente a UI sobre mudanças no banco de dados — esta é uma diferença chave das solicitações únicas onde a UI não sabe sobre mudanças sem atualização manual.

DataSource: Remote, Local e cache de dados

DataSource — classes responsáveis por trabalhar com uma fonte de dados específica. RemoteDataSource usa um cliente HTTP (URLSession, Retrofit, Ktor) para obter dados da API. LocalDataSource trabalha com armazenamento local (CoreData, Realm, Room, UserDefaults, DataStore). Cada DataSource tem uma responsabilidade estreita: RemoteDataSource conhece apenas o formato da solicitação da API, LocalDataSource — o esquema do banco de dados. O Repository os combina, implementando uma estratégia de cache.

DataSourcePlataforma iOSPlataforma AndroidFonte
RemoteURLSession + CodableRetrofit + Moshi/GsonAPI REST / GraphQL
Local (BD)CoreData, SwiftDataRoom, SQLDelightSQLite no dispositivo
Local (cache)NSCache, UserDefaultsDataStore, EncryptedSPEm memória / disco
PreferênciasUserDefaults, KeychainSharedPreferences, EncryptedSPConfigurações, tokens

Estratégias de cache no Repository: Cache-First (cache primeiro, depois carregamento em segundo plano), Network-Only (apenas rede, para telas de pagamento), Network-First-With-Cache-Backup (rede primeiro, fallback para cache em caso de erro). A escolha da estratégia depende do cenário: uma lista de países pode ser armazenada em cache por muito tempo, taxas de câmbio — por 15 minutos, saldo da carteira — apenas da rede. O Repository implementa a estratégia e a altera sem modificar a ViewModel ou a UI.

Repository Pattern vs Service Layer: diferenças e escolha

Repository e Service são padrões diferentes com funções sobrepostas. Repository é responsável pelo acesso a dados e cache, retornando modelos de dados. Service (ou Interactor, Use Case) contém lógica de negócios: validação, transformação de dados, orquestração de chamadas a vários Repositories. Service pode combinar UserRepository, OrderRepository e NotificationRepository para processar um pedido. Repository não contém lógica de negócios — apenas CRUD e cache.

Quando escolher Repository — navegação de dados com múltiplas fontes (API + BD + cache), arquitetura offline-first, necessidade de cache e alternância transparente de fontes. Repository é obrigatório na Clean Architecture e recomendado pelo Google para aplicações Android. Na arquitetura VIPER em iOS, o papel do Repository é desempenhado pela camada Interactor, que interage com Manager ou Service para acesso a dados.

Quando Service é suficiente — aplicações simples com uma única fonte de dados, telas somente leitura sem escrita, projetos sem modo offline. Nesses casos, DataSource é usado diretamente pela ViewModel ou Presenter, e Repository torna-se uma camada desnecessária. No entanto, adicionar Repository no início não requer esforço significativo e simplifica a adição de cache e testes no futuro.

Perguntas frequentes

Como Repository difere de DataSource?

DataSource é uma classe que trabalha com uma única fonte (API, BD, cache). Repository é uma classe que gerencia múltiplos DataSources e fornece uma interface unificada. O Repository decide qual DataSource usar e coordena o cache. DataSource não conhece a existência de outras fontes; Repository não conhece os detalhes de implementação de cada fonte.

Repository é necessário em iOS com SwiftUI?

Sim, Repository é útil em SwiftUI para separar dados da View. A ViewModel assina um Publisher do Repository, e o Repository gerencia cache e sincronização. Em aplicações simples, URLSession pode ser usado diretamente na ViewModel, mas para testabilidade e escalabilidade, Repository é preferível. A Apple não impõe o padrão, mas ele é compatível com SwiftData e Network.framework.

Como testar Repository com múltiplos DataSources?

DataSources são substituídos por objetos mock através de Injeção de Dependência. O teste cria um RemoteDataSource mock (retorna JSON predefinido) e um LocalDataSource mock (verifica se os dados foram salvos). O Repository é testado isoladamente: a estratégia de cache, tratamento de erros e ordem correta de chamadas são verificados. Para testes de integração, usa-se TestDispatcher (Kotlin) ou MainActor.run (Swift).

Pode-se usar Repository sem interface (protocolo)?

É possível, mas não recomendado. Sem um protocolo, é impossível substituir a implementação em testes e previews. Em Kotlin, a interface Repository permite substituir a implementação via DI (Dagger, Hilt, Koin). Em Swift, o protocolo Repository é obrigatório para testar código async-await e Combine. A exceção são projetos simples com uma única fonte de dados onde Repository não tem lógica de cache.

O que é offline-first no contexto do Repository?

Offline-first é uma estratégia onde a aplicação funciona sem internet usando dados locais. Repository desempenha um papel chave: primeiro retorna dados do DataSource local e depois sincroniza com o servidor em segundo plano. O usuário vê os dados instantaneamente, e o Repository os atualiza após carregar da rede. Room com Flow fornece atualizações reativas da UI quando os dados mudam no banco de dados local.

Resumo

  • Repository Pattern — uma camada de abstração entre a UI e as fontes de dados
  • DataSource — classes separadas para API, BD e cache
  • Protocolos — necessários para testes e substituição de implementações
  • Estratégias de cache — Cache-First, Network-Only, Network-First-With-Cache-Backup
  • iOS — async-await ou Combine com protocolos
  • Android — Kotlin Flow + Room + Retrofit, abordagem recomendada pelo Google
  • Testes — DataSources mock via DI, verificar estratégias de cache

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também