Adapter — nedir, mobil geliştirme için arayüz dönüştürme deseni

Yazar: IT Sectr Yayınlanma: 2026-02-18 Okuma süresi: 10 dk

Adapter, bir sınıfın arayüzünü istemcinin beklediği başka bir arayüze dönüştüren yapısal bir tasarım desenidir. Mobil geliştirmede Adapter, en sık Android'de RecyclerView.Adapter ve iOS'te UITableViewDataSource olarak kullanılır. Google I/O (2024)'ya göre, RecyclerView Android uygulamalarının %95'inde listeleri görüntülemek için kullanılır ve her biri kendi Adapter uygulamasını gerektirir.

Önemli Noktalar

  • Adapter, uyumsuz arayüzlere sahip nesnelerin birlikte çalışmasını sağlayan yapısal bir desendir
  • RecyclerView.Adapter, Android'de desenin bir uygulamasıdır, verileri liste için ViewHolder'lara dönüştürür
  • UITableViewDataSource, iOS'te bir uygulamadır, Adapter ve DataSource desenlerini birleştirir
  • Object Adapter kompozisyon kullanır: adaptör, uyarlanan nesneye bir referans içerir
  • Class Adapter çoklu kalıtım kullanır — yalnızca C++'da mümkündür, Java/Swift/Kotlin'de kullanılamaz

Adapter Deseni Nedir?

Adapter, arayüz uyumsuzluğu sorununu çözen yapısal bir desendir. Bir nesneyi (Adaptee), istemcinin beklediği arayüze (Target) sahip bir sınıfa (Adapter) sarar. İstemci, Target ile çalışır ve Adaptee'nin varlığından habersizdir. Bu, Wrapper deseninin bir çeşididir.

Kotlin
// Uyumsuz arayüze sahip mevcut sınıf
class LegacyAuthApi {
    fun loginWithToken(token: String): Map {
        return mapOf("status" to "ok", "user_id" to 42)
    }
}

// Hedef arayüz (istemcinin beklediği)
interface AuthService {
    suspend fun login(credentials: Credentials): Result
}

// Adapter — LegacyAuthApi'yi AuthService'e dönüştürür
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, eski API için login(credentials) çağrısını loginWithToken(token)'a dönüştürür. İstemci (ViewModel), AuthService arayüzü üzerinden çalışır ve altında en yeni Firebase Auth mu yoksa on yıllık eski bir API mi olduğunu bilmez. Bu, istemci kodunu değiştirmeden uygulamaların değiştirilmesine olanak tanır.

Android'de Adapter: RecyclerView ve ListAdapter

RecyclerView.Adapter, Android'de Adapter deseninin en yaygın uygulamasıdır. Verileri (nesne listesi), RecyclerView'in ekranda görüntülediği ViewHolder'lara dönüştürür. ListAdapter'ın (Android Architecture Components) tanıtılmasıyla, desen değişiklikleri canlandırmak için yerleşik fark hesaplama desteği kazandı.

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, verimli liste yeniden çizimi için DiffUtil ile ListAdapter kullanır. Veriler güncellendiğinde, DiffCallback eski ve yeni liste arasındaki farkı hesaplar ve RecyclerView yalnızca değişen öğeleri canlandırır — tüm listeyi yeniden çizmeden. Bu, manuel notifyDataSetChanged() gerektiren eski ListView'a göre önemli bir avantajdır.

iOS'te Adapter: UITableView ve DiffableDataSource

UITableViewDataSource, aynı anda hem Adapter deseni hem de DataSource desenidir. Model verilerini tablo hücrelerine dönüştürür. iOS 13'ten itibaren Apple, DiffableDataSource'ı tanıttı — Android'deki ListAdapter gibi, değişiklikleri otomatik olarak hesaplayan ve güncellemeleri canlandıran modern bir alternatif.

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
    }
}

// Modern sürüm: 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, DiffableDataSource ile veriler güncellendiğinde değişiklikleri otomatik olarak canlandırır: öğeler akıcı animasyonlarla görünür, kaybolur veya hareket eder. iOS'in DiffableDataSource'u ve Android'in ListAdapter'i farklı API'lerle aynı sorunu çözer ancak aynı mantıkla — fark hesaplama + otomatik animasyon.

Object Adapter vs Class Adapter

Object Adapter kompozisyon kullanır: adaptör, Adaptee nesnesine bir referans içerir ve çağrıları ona devreder. Class Adapter kalıtım kullanır: adaptör, Adaptee'den miras alır ve aynı anda hedef arayüzü uygular. Java, Swift ve Kotlin'de, çoklu kalıtım eksikliği nedeniyle Class Adapter imkansızdır — yalnızca Object Adapter kalır.

ÖzellikObject AdapterClass Adapter
MekanizmaKompozisyon (Adaptee'yi içerir)Kalıtım (Adaptee'yi genişletir)
EsneklikDaha yüksek — Adaptee çalışma zamanında değiştirilebilirDaha düşük — Adaptee derleme zamanında sabittir
BağlılıkZayıf (arayüz aracılığıyla)Güçlü (kalıtım aracılığıyla)
Alt sınıf uyarlamasıEvet — Adaptee herhangi bir alt sınıf olabilirHayır — yalnızca belirli bir üst sınıf
KullanılabilirlikJava, Kotlin, Swift, C++, C#Yalnızca çoklu kalıtımlı diller (C++)

Mobil geliştirmede yalnızca Object Adapter kullanılır. RecyclerView.Adapter, verilere ve LayoutInflater'a referanslar içerir, UITableViewDataSource bir öğe dizisi içerir. Kompozisyon, kalıtıma kıyasla kodu daha esnek ve test edilebilir hale getirir.

Gerçek Projelerde Adapter Örnekleri

Adapter yalnızca listeler için kullanılmaz. Desenin uyumsuz bileşenleri entegre etme sorununu çözdüğü mobil geliştirme pratiğinden üç senaryoyu inceleyelim.

SenaryoAdapteeTargetAdapter
Eski auth kütüphanesinin entegrasyonuLegacyAuthLib (callback tabanlı)AuthService (suspend)LegacyAuthAdapter
JSON'ın yeni modele uyarlanmasıGsonParserJsonParser (Kotlinx Serialization)GsonAdapter
Push hizmetleri için birleşik arayüzFCM, APNs, Huawei PushPushService token registerPushServiceAdapter

Her Adaptör dönüştürme mantığını kapsüller: GsonAdapter, @SerializedName aracılığıyla JSON dizesini nesneye çevirir, PushServiceAdapter farklı platformlar için token kaydını soyutlar. İstemci (iş mantığı) birleşik bir arayüzle çalışır ve belirli uygulamaya bağlı değildir.

Adapter Uygularken Sık Yapılan Hatalar

Adapter uygulamasındaki hatalar, liste yavaşlamalarına, bellek sızıntılarına ve veri güncelleme hatalarına yol açar. Üç yaygın sorunu inceleyelim.

onBindViewHolder'da ağır işlemler

onBindViewHolder, kaydırma sırasında her hücre için çağrılır. Bu yöntemde nesne oluşturma, JSON ayrıştırma veya veritabanı çağrısı kare düşüşlerine (frame drops) neden olur. Çözüm: tüm ağır hesaplamaları önceden yapın, adaptöre hazır verileri iletin. Görüntüler için önbellekleme kütüphaneleri kullanın — Glide, Coil, Kingfisher.

DiffUtil / DiffableDataSource'u görmezden gelmek

Her güncellemede notifyDataSetChanged() çağırmak tüm listeyi yeniden çizer, titremeye ve girişlerde odak kaybına neden olur. Çözüm: Android'de DiffUtil ile ListAdapter veya iOS'te DiffableDataSource kullanın. Fark hesaplaması, 1000 öğeye kadar listeler için <1 ms sürer ve akıcı animasyonlar sağlar.

Adaptörde ağır nesneler depolamak

Adaptör, RecyclerView/UITableView kadar yaşar. Adaptörde Bitmap veya büyük diziler depolamak, yapılandırma değişikliklerinde (ekran dönüşü, tema değişikliği) bellek sızıntılarına yol açar. Çözüm: adaptör yalnızca hafif veri modellerini (data class / struct) depolamalı ve ağır kaynakları ihtiyaç halinde ViewHolder aracılığıyla yüklemelidir.

Sıkça Sorulan Sorular

Adapter ve Proxy arasındaki fark nedir?

Adapter, Adaptee arayüzünü Target arayüzüne dönüştürür — istemci yeni bir etkileşim yöntemi elde eder. Proxy, orijinal nesneyle aynı arayüzü sağlar ancak erişim kontrolü, önbellekleme veya geç başlatma ekler. Proxy arayüzü değiştirmez, Adapter değiştirir.

RecyclerView.Adapter neden Adapter desenine bir örnektir?

RecyclerView.Adapter, verileri (örneğin, User listesi) RecyclerView'in görüntüleyebileceği bir ViewHolder'a dönüştürür. RecyclerView bir ViewHolder bekler, veriler List<User> biçimindedir — Adapter birini diğerine uyarlar. Ek olarak, Adapter, geri dönüşüm havuzu aracılığıyla ViewHolder yaşam döngüsünü yöneterek liste performansını artırır.

Object Adapter ve Class Adapter arasındaki fark nedir?

Object Adapter kompozisyon kullanır: Adaptee'ye bir referans içerir ve çağrıları ona devreder. Class Adapter çoklu kalıtım kullanır: Adaptee'den miras alır ve Target'ı uygular. Java, Kotlin ve Swift'te, çoklu sınıf kalıtımı eksikliği nedeniyle yalnızca Object Adapter kullanılabilir. Class Adapter yalnızca C++'da mümkündür.

Facade yerine ne zaman Adapter kullanılır?

Adapter, iki mevcut sınıfın birlikte çalışmasını sağlamak için bunlardan birinin arayüzünü dönüştürerek kullanılır. Facade, basit bir arayüz sağlayarak karmaşık bir alt sistemle etkileşimi basitleştirmek gerektiğinde kullanılır. Adapter uyumluluk için, Facade basitleştirme içindir.

Adapter arayüz olmadan uygulanabilir mi?

Evet, closure'lar kullanarak. Tek yöntemli bir arayüz yerine bir işlev iletilebilir. Örneğin, Swift'te: let adapter = { (data: Data) -> [CellConfig] in /* dönüştürme */ }. Bu yaklaşıma işlevsel adaptör denir. Ancak, 2+ yöntem için bir protokol/arayüz tercih edilir — sözleşmeyi açık hale getirir.

Özet

  • Adapter, uyumsuz bir Adaptee arayüzünü bir ara sınıf aracılığıyla Target'a dönüştüren yapısal bir desendir
  • RecyclerView.Adapter (Android) ve UITableViewDataSource (iOS), mobil geliştirmede desenin ana örnekleridir
  • Object Adapter kompozisyon kullanır; Class Adapter (yalnızca C++) çoklu kalıtım kullanır
  • ListAdapter + DiffUtil (Android) ve DiffableDataSource (iOS), otomatik fark ve animasyonlu modern evrimlerdir
  • onBindViewHolder'da ağır işlemler, DiffUtil'ı görmezden gelmek ve adaptörde kaynak depolamak yaygın hatalardır
  • Adapter, eski kod entegrasyonu, biçim uyarlaması ve farklı uygulamaları birleştirmek için kullanılır
  • Öneri: manuel liste güncelleme yönetimi yerine ListAdapter/DiffableDataSource kullanın

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun