Adapter — o que é, o padrão de transformação de interfaces para desenvolvimento móvel

Autor: IT Sectr Publicado: 2026-02-18 Tempo de leitura: 10 min

Adapter é um padrão de design estrutural que converte a interface de uma classe em outra interface esperada pelo cliente. No desenvolvimento móvel, Adapter é mais frequentemente usado em RecyclerView.Adapter para Android e UITableViewDataSource para iOS. De acordo com o Google I/O (2024), RecyclerView é usado em 95% dos aplicativos Android para exibir listas, e cada um requer sua própria implementação de Adapter.

Pontos principais

  • Adapter é um padrão estrutural que permite que objetos com interfaces incompatíveis trabalhem juntos
  • RecyclerView.Adapter é uma implementação do padrão no Android, convertendo dados em ViewHolders para a lista
  • UITableViewDataSource é uma implementação no iOS, combinando os padrões Adapter e DataSource
  • Object Adapter usa composição: o adaptador contém uma referência ao objeto adaptado
  • Class Adapter usa herança múltipla — possível apenas em C++, não disponível em Java/Swift/Kotlin

O que é o padrão Adapter?

Adapter é um padrão estrutural que resolve o problema de incompatibilidade de interfaces. Ele envolve um objeto (Adaptee) em uma classe (Adapter) com a interface esperada pelo cliente (Target). O cliente trabalha com Target sem saber da existência de Adaptee. É uma variante do padrão Wrapper.

Kotlin
// Classe existente com interface incompatível
class LegacyAuthApi {
    fun loginWithToken(token: String): Map {
        return mapOf("status" to "ok", "user_id" to 42)
    }
}

// Interface alvo (o que o cliente espera)
interface AuthService {
    suspend fun login(credentials: Credentials): Result
}

// Adapter — transforma LegacyAuthApi em AuthService
class LegacyAuthAdapter(
    private val legacyApi: LegacyAuthApi
) : AuthService {
    override suspend fun login(credentials: Credentials): Result {
        val token = "${credentials.login}:${credentials.password}"
            .encodeToByteArray().let { Base64.encodeToString(it) }
        val response = legacyApi.loginWithToken(token)
        return if (response["status"] == "ok") {
            Result.success(User(response["user_id"] as Int))
        } else {
            Result.failure(AuthException("Login failed"))
        }
    }
}

LegacyAuthAdapter converte a chamada login(credentials) em loginWithToken(token) para a API antiga. O cliente (ViewModel) trabalha através da interface AuthService e não sabe se por baixo está o mais recente Firebase Auth ou uma API legada de uma década atrás. Isso permite substituir implementações sem alterar o código do cliente.

Adapter no Android: RecyclerView e ListAdapter

RecyclerView.Adapter é a implementação mais comum do padrão Adapter no Android. Ele converte dados (uma lista de objetos) em ViewHolders que o RecyclerView exibe na tela. Com a introdução do ListAdapter (Android Architecture Components), o padrão ganhou suporte embutido para cálculo de diferenças (diff) para animar alterações.

Kotlin
class UserAdapter(
    private val onItemClick: (User) -> Unit
) : ListAdapter(DiffCallback()) {

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): UserViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_user, parent, false)
        return UserViewHolder(view)
    }

    override fun onBindViewHolder(
        holder: UserViewHolder,
        position: Int
    ) {
        holder.bind(getItem(position), onItemClick)
    }

    class UserViewHolder(itemView: View) :
        RecyclerView.ViewHolder(itemView) {
        
        private val tvName = itemView.findViewById(R.id.tvName)
        
        fun bind(user: User, click: (User) -> Unit) {
            tvName.text = user.name
            itemView.setOnClickListener { click(user) }
        }
    }

    private class DiffCallback : DiffUtil.ItemCallback() {
        override fun areItemsTheSame(old: User, new: User) = old.id == new.id
        override fun areContentsTheSame(old: User, new: User) = old == new
    }
}

UserAdapter usa ListAdapter com DiffUtil para redesenho eficiente da lista. Quando os dados são atualizados, DiffCallback calcula a diferença entre a lista antiga e a nova, e o RecyclerView anima apenas os itens alterados — sem redesenhar a lista inteira. Esta é uma vantagem chave sobre o ListView antigo, que exigia notifyDataSetChanged() manual.

Adapter no iOS: UITableView e DiffableDataSource

UITableViewDataSource é ao mesmo tempo o padrão Adapter e o padrão DataSource. Ele converte dados do modelo em células de tabela. Desde o iOS 13, a Apple introduziu o DiffableDataSource — uma substituição moderna que, como o ListAdapter no Android, calcula automaticamente as alterações e anima as atualizações.

Swift
class UserTableViewAdapter: NSObject, UITableViewDataSource {
    var items: [User] = []
    
    func tableView(_ tableView: UITableView,
                    numberOfRowsInSection section: Int) -> Int {
        items.count
    }
    
    func tableView(_ tableView: UITableView,
                    cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(
            withIdentifier: "UserCell", for: indexPath)
        let user = items[indexPath.row]
        cell.textLabel?.text = user.name
        return cell
    }
}

// Versão moderna: DiffableDataSource
enum Section { case main }

class ModernUserAdapter {
    var dataSource: UITableViewDiffableDataSource<Section, User>!
    
    func configure(for tableView: UITableView) {
        dataSource = UITableViewDiffableDataSource(
            tableView: tableView
        ) { tableView, indexPath, user in
            let cell = tableView.dequeueReusableCell(
                withIdentifier: "UserCell", for: indexPath)
            cell.textLabel?.text = user.name
            return cell
        }
    }
    
    func update(with users: [User]) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, User>()
        snapshot.appendSections([.main])
        snapshot.appendItems(users)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}

ModernUserAdapter com DiffableDataSource anima automaticamente as alterações quando os dados são atualizados: os itens aparecem, desaparecem ou se movem com animações suaves. O DiffableDataSource do iOS e o ListAdapter do Android resolvem o mesmo problema com APIs diferentes, mas a mesma lógica — cálculo de diferenças + animação automática.

Object Adapter vs Class Adapter

Object Adapter usa composição: o adaptador contém uma referência ao objeto Adaptee e delega chamadas a ele. Class Adapter usa herança: o adaptador herda de Adaptee e implementa a interface alvo simultaneamente. Em Java, Swift e Kotlin, Class Adapter é impossível devido à falta de herança múltipla — apenas Object Adapter permanece.

CaracterísticaObject AdapterClass Adapter
MecanismoComposição (contém Adaptee)Herança (estende Adaptee)
FlexibilidadeMaior — Adaptee pode ser alterado em tempo de execuçãoMenor — Adaptee é fixo em tempo de compilação
AcoplamentoFraco (via interface)Forte (via herança)
Adaptação de subclassesSim — Adaptee pode ser qualquer subclasseNão — apenas uma superclasse específica
DisponibilidadeJava, Kotlin, Swift, C++, C#Apenas linguagens com herança múltipla (C++)

No desenvolvimento móvel, apenas Object Adapter é usado. RecyclerView.Adapter contém referências a dados e LayoutInflater, UITableViewDataSource contém um array de itens. A composição torna o código mais flexível e testável em comparação com a herança.

Exemplos de Adapter em projetos reais

Adapter não é usado apenas para listas. Vamos considerar três cenários da prática de desenvolvimento móvel onde o padrão resolve o problema de integrar componentes incompatíveis.

CenárioAdapteeTargetAdapter
Integração de biblioteca auth legadaLegacyAuthLib (baseada em callbacks)AuthService (suspend)LegacyAuthAdapter
Adaptação de JSON para novo modeloGsonParserJsonParser (Kotlinx Serialization)GsonAdapter
Interface unificada para serviços pushFCM, APNs, Huawei PushPushService token registerPushServiceAdapter

Cada Adapter encapsula a lógica de conversão: GsonAdapter traduz uma string JSON em um objeto via @SerializedName, PushServiceAdapter abstrai o registro de token para diferentes plataformas. O cliente (lógica de negócios) trabalha com uma interface unificada e não depende da implementação específica.

Erros comuns ao implementar Adapter

Erros na implementação de Adapter levam a lentidão em listas, vazamentos de memória e bugs com atualizações de dados. Vamos ver três problemas comuns.

Operações pesadas em onBindViewHolder

onBindViewHolder é chamado para cada célula durante a rolagem. Criar objetos, analisar JSON ou chamar o banco de dados neste método leva a quedas de quadros (frame drops). Solução: realize todos os cálculos pesados antecipadamente, passando dados prontos para o adaptador. Use bibliotecas de cache para imagens — Glide, Coil, Kingfisher.

Ignorar DiffUtil / DiffableDataSource

Chamar notifyDataSetChanged() em cada atualização redesenha a lista inteira, causando oscilação e perda de foco em entradas. Solução: use ListAdapter com DiffUtil no Android ou DiffableDataSource no iOS. O cálculo de diferenças leva <1 ms para listas de até 1000 itens e garante animações suaves.

Armazenar objetos pesados no adaptador

O adaptador vive enquanto o RecyclerView/UITableView existir. Armazenar Bitmaps ou arrays grandes no adaptador leva a vazamentos de memória em mudanças de configuração (rotação de tela, mudança de tema). Solução: o adaptador deve armazenar apenas modelos de dados leves (data class / struct), e carregar recursos pesados através do ViewHolder sob demanda.

Perguntas frequentes

Qual a diferença entre Adapter e Proxy?

Adapter converte a interface de Adaptee para a interface de Target — o cliente obtém uma nova forma de interação. Proxy fornece a mesma interface que o objeto original, mas adiciona controle de acesso, cache ou inicialização preguiçosa. Proxy não altera a interface, Adapter altera.

Por que RecyclerView.Adapter é um exemplo do padrão Adapter?

RecyclerView.Adapter converte dados (por exemplo, uma lista de User) em um ViewHolder que o RecyclerView pode exibir. RecyclerView espera um ViewHolder, os dados estão no formato List<User> — o Adapter adapta um ao outro. Além disso, o Adapter gerencia o ciclo de vida do ViewHolder através do pool de reciclagem, melhorando o desempenho da lista.

Qual a diferença entre Object Adapter e Class Adapter?

Object Adapter usa composição: contém uma referência a Adaptee e delega chamadas a ele. Class Adapter usa herança múltipla: herda de Adaptee e implementa Target. Em Java, Kotlin e Swift, apenas Object Adapter está disponível devido à falta de herança múltipla de classes. Class Adapter só é possível em C++.

Quando usar Adapter em vez de Facade?

Adapter é usado quando você precisa fazer duas classes existentes funcionarem juntas convertendo a interface de uma delas. Facade é usado quando você precisa simplificar a interação com um subsistema complexo fornecendo uma interface simples. Adapter é para compatibilidade, Facade é para simplificação.

Pode-se implementar Adapter sem interface?

Sim, usando closures. Em vez de uma interface com um método, você pode passar uma função. Por exemplo, em Swift: let adapter = { (data: Data) -> [CellConfig] in /* conversão */ }. Esta abordagem é chamada de adaptador funcional. No entanto, para 2+ métodos, um protocolo/interface continua preferível — torna o contrato explícito.

Resumo

  • Adapter é um padrão estrutural que converte uma interface Adaptee incompatível em um Target através de uma classe intermediária
  • RecyclerView.Adapter (Android) e UITableViewDataSource (iOS) são os principais exemplos do padrão no desenvolvimento móvel
  • Object Adapter usa composição; Class Adapter (apenas C++) usa herança múltipla
  • ListAdapter + DiffUtil (Android) e DiffableDataSource (iOS) são evoluções modernas com diff automático e animação
  • Operações pesadas em onBindViewHolder, ignorar DiffUtil e armazenar recursos no adaptador são erros comuns
  • Adapter é usado para integrar código legado, adaptar formatos e unificar diferentes implementações
  • Recomendação: use ListAdapter/DiffableDataSource em vez do gerenciamento manual de atualizações de lista

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