Adapter — bu nədir, mobil inkişaf üçün interfeys çevirmə nümunəsi

Müəllif: IT Sectr Dərc olunub: 2026-02-18 Oxuma vaxtı: 10 dəq

Adapter — bir sinfin interfeysini müştərinin gözlədiyi başqa interfeysə çevirən struktur layihə nümunəsidir. Mobil inkişafda Adapter ən çox Android üçün RecyclerView.Adapter və iOS üçün UITableViewDataSource-da istifadə olunur. Google I/O (2024) məlumatlarına görə, RecyclerView Android tətbiqlərinin 95%-də siyahıları göstərmək üçün istifadə olunur və hər biri öz Adapter tətbiqini tələb edir.

Əsas məqamlar

  • Adapter — uyğun olmayan interfeyslərə malik obyektlərin birlikdə işləməsinə imkan verən struktur nümunə
  • RecyclerView.Adapter — Android-də nümunənin tətbiqi, məlumatları siyahı üçün ViewHolder-a çevirir
  • UITableViewDataSource — iOS-da Adapter və DataSource nümunələrini birləşdirən tətbiq
  • Object Adapter kompozisiyadan istifadə edir: adapter uyğunlaşdırılan obyektə istinad saxlayır
  • Class Adapter çoxlu mirasdan istifadə edir — yalnız C++-da mümkündür, Java/Swift/Kotlin-də mövcud deyil

Adapter nümunəsi nədir?

Adapter — interfeys uyğunsuzluğu problemini həll edən struktur nümunədir. Bir obyekti (Adaptee) müştərinin gözlədiyi interfeysə (Target) malik sinfə (Adapter) bükür. Müştəri Adaptee-nin mövcudluğundan xəbərsiz Target ilə işləyir. Bu Wrapper nümunəsinin bir növüdür.

Kotlin
// Uyğun olmayan interfeysə malik mövcud sinif
class LegacyAuthApi {
    fun loginWithToken(token: String): Map {
        return mapOf("status" to "ok", "user_id" to 42)
    }
}

// Hədəf interfeys (müştərinin gözlədiyi)
interface AuthService {
    suspend fun login(credentials: Credentials): Result
}

// Adapter — LegacyAuthApi-ni AuthService-ə çevirir
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 köhnə API üçün login(credentials) çağırışını loginWithToken(token)-a çevirir. Müştəri (ViewModel) AuthService interfeysi vasitəsilə işləyir və onun altında ən yeni Firebase Auth və ya on illik köhnə API olduğunu bilmir. Bu, müştəri kodunu dəyişmədən tətbiqləri əvəz etməyə imkan verir.

Android-də Adapter: RecyclerView və ListAdapter

RecyclerView.Adapter — Android-də Adapter nümunəsinin ən geniş yayılmış tətbiqidir. Məlumatları (obyekt siyahısını) RecyclerView-in ekranda göstərdiyi ViewHolder-lərə çevirir. ListAdapter-in (Android Architecture Components) meydana gəlməsi ilə nümunə dəyişiklik animasiyası üçün daxili diff hesablama dəstəyi aldı.

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 səmərəli siyahı yenidən çəkilməsi üçün DiffUtil ilə ListAdapter-dən istifadə edir. Məlumatlar yeniləndikdə, DiffCallback köhnə və yeni siyahı arasındakı fərqi hesablayır və RecyclerView yalnız dəyişdirilmiş elementləri animasiya edir — bütün siyahını yenidən çəkmədən. Bu, əl ilə notifyDataSetChanged() tələb edən köhnə ListView-dən əsas üstünlükdür.

iOS-da Adapter: UITableView və DiffableDataSource

UITableViewDataSource — eyni zamanda həm Adapter, həm də DataSource nümunəsidir. Model məlumatlarını cədvəl hüceyrələrinə çevirir. iOS 13-dən etibarən Apple DiffableDataSource-u təqdim etdi — Android-də ListAdapter kimi dəyişiklikləri avtomatik hesablayan və yeniləmələri animasiya edən müasir əvəz.

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

// Müasir versiya: 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 ilə məlumatlar yeniləndikdə dəyişiklikləri avtomatik animasiya edir: elementlər hamar animasiyalarla görünür, yox olur və ya hərəkət edir. iOS DiffableDataSource və Android ListAdapter eyni tapşırığı müxtəlif API-lərlə, lakin eyni məntiqlə — diff hesablama + avtomatik animasiya ilə həll edir.

Object Adapter vs Class Adapter

Object Adapter kompozisiyadan istifadə edir: adapter Adaptee obyektinə istinad saxlayır və ona çağırışları həvalə edir. Class Adapter mirasdan istifadə edir: adapter Adaptee-dən miras alır və eyni zamanda hədəf interfeysi tətbiq edir. Java, Swift və Kotlin-də Class Adapter çoxlu mirasın olmaması səbəbindən mümkün deyil — yalnız Object Adapter qalır.

XüsusiyyətObject AdapterClass Adapter
MexanizmKompozisiya (Adaptee-ni ehtiva edir)Miras (extends Adaptee)
ÇeviklikDaha yüksək — Adaptee runtime-da dəyişdirilə bilərDaha aşağı — Adaptee kompilyasiya mərhələsində sabitdir
BağlılıqZəif (interfeys vasitəsilə)Güclü (miras vasitəsilə)
Alt siniflərin adaptasiyasıBəli — Adaptee istənilən alt sinif ola bilərXeyr — yalnız konkret super sinif
MövcudluqJava, Kotlin, Swift, C++, C#Yalnız çoxlu miraslı dillər (C++)

Mobil inkişafda yalnız Object Adapter istifadə olunur. RecyclerView.Adapter məlumatlara və LayoutInflater-ə istinadlar saxlayır, UITableViewDataSource elementlər massivi saxlayır. Kompozisiya kodu mirasla müqayisədə daha çevik və test edilə bilən edir.

Real layihələrdə Adapter nümunələri

Adapter təkcə siyahılar üçün tətbiq edilmir. Mobil inkişaf təcrübəsindən üç ssenarini nəzərdən keçirək, burada nümunə uyğun olmayan komponentlərin inteqrasiyası problemini həll edir.

SsenariAdapteeTargetAdapter
Köhnə auth kitabxanasının inteqrasiyasıLegacyAuthLib (callback-based)AuthService (suspend)LegacyAuthAdapter
JSON-un yeni modelə uyğunlaşdırılmasıGsonParserJsonParser (Kotlinx Serialization)GsonAdapter
Push xidmətləri üçün vahid interfeysFCM, APNs, Huawei PushPushService token registerPushServiceAdapter

Hər bir Adapter çevirmə məntiqini kapsullaşdırır: GsonAdapter JSON sətrini @SerializedName vasitəsilə obyektə çevirir, PushServiceAdapter müxtəlif platformalar üçün token qeydiyyatını abstraksiya edir. Müştəri (biznes məntiqi) vahid interfeyslə işləyir və konkret tətbiqdən asılı deyil.

Adapter tətbiqində tipik səhvlər

Adapter tətbiqində səhvlər siyahıların ləngiməsinə, yaddaş sızmalarına və məlumat yeniləmə xətalarına səbəb olur. Üç ümumi problemi nəzərdən keçirək.

onBindViewHolder-da ağır əməliyyatlar

onBindViewHolder sürüşdürmə zamanı hər bir hüceyrə üçün çağırılır. Bu metoddakı obyekt yaratma, JSON pars etmə və ya verilənlər bazası sorğuları siyahının sıçramasına (frame drops) səbəb olur. Həll yolu: bütün ağır hesablamaları əvvəlcədən aparmaq, adapterə artıq hazır məlumatları ötürmək. Şəkillər üçün keşləmə kitabxanalarından istifadə edin — Glide, Coil, Kingfisher.

DiffUtil / DiffableDataSource-a məhəl qoymama

Hər yeniləmədə notifyDataSetChanged() çağırmaq bütün siyahını yenidən çəkir, yanıb-sönməyə və giriş sahələrində fokus itkisinə səbəb olur. Həll yolu: Android-də DiffUtil ilə ListAdapter və ya iOS-da DiffableDataSource istifadə edin. Diff hesablama 1000 elementə qədər siyahılar üçün <1 ms çəkir və hamar animasiyalar təmin edir.

Adapterdə ağır obyektlərin saxlanması

Adapter RecyclerView/UITableView qədər yaşayır. Adapterdə Bitmap və ya böyük massivlərin saxlanması konfiqurasiya dəyişikliyi (ekranın döndərilməsi, mövzu dəyişikliyi) zamanı yaddaş sızmalarına səbəb olur. Həll yolu: adapter yalnız yüngül məlumat modellərini (data class / struct) saxlamalı, ağır resursları isə ViewHolder vasitəsilə tələb əsasında yükləməlidir.

Tez-tez verilən suallar

Adapter və Proxy arasında fərq nədir?

Adapter Adaptee interfeysini Target interfeysinə çevirir — müştəri yeni qarşılıqlı əlaqə üsulu alır. Proxy orijinal obyektlə eyni interfeysi təqdim edir, lakin giriş nəzarəti, keşləmə və ya tənbəl inisializasiya əlavə edir. Proxy interfeysi dəyişmir, Adapter — dəyişir.

Niyə RecyclerView.Adapter Adapter nümunəsinin nümunəsidir?

RecyclerView.Adapter məlumatları (məsələn, User siyahısını) RecyclerView-in göstərə biləcəyi ViewHolder-a çevirir. RecyclerView ViewHolder gözləyir, məlumatlar List<User> formatındadır — Adapter birini digərinə uyğunlaşdırır. Əlavə olaraq, Adapter ViewHolder-ın həyat dövrünü təkrar istifadə hovuzu vasitəsilə idarə edərək siyahının performansını artırır.

Object Adapter və Class Adapter arasında fərq nədir?

Object Adapter kompozisiyadan istifadə edir: Adaptee-yə istinad saxlayır və ona çağırışları həvalə edir. Class Adapter çoxlu mirasdan istifadə edir: Adaptee-dən miras alır və Target-i tətbiq edir. Java, Kotlin və Swift-də siniflərin çoxlu mirasının olmaması səbəbindən yalnız Object Adapter mövcuddur. Class Adapter yalnız C++-da mümkündür.

Adapter nə vaxt Facade əvəzinə istifadə edilməlidir?

Adapter iki mövcud sinfin birlikdə işləməsini təmin etmək üçün onlardan birinin interfeysini çevirərkən istifadə olunur. Facade — mürəkkəb alt sistemlə qarşılıqlı əlaqəni sadələşdirmək, sadə interfeys təmin etmək üçün istifadə olunur. Adapter — uyğunluq üçün, Facade — sadələşdirmə üçün.

Adapter interfeys olmadan həyata keçirilə bilərmi?

Bəli, bağlanmalar (closures) vasitəsilə. Bir metodlu interfeys əvəzinə funksiya ötürmək olar. Məsələn, Swift-də: let adapter = { (data: Data) -> [CellConfig] in /* çevirmə */ }. Belə yanaşma functional adapter adlanır. Lakin 2+ metod üçün protokol/interfeys üstünlük təşkil edir — müqaviləni aşkar edir.

Nəticə

  • Adapter — uyğun olmayan Adaptee interfeysini aralıq sinif vasitəsilə Target-ə çevirən struktur nümunə
  • RecyclerView.Adapter (Android) və UITableViewDataSource (iOS) — mobil inkişafda nümunənin əsas nümunələri
  • Object Adapter kompozisiyadan istifadə edir; Class Adapter (yalnız C++) — çoxlu miras
  • ListAdapter + DiffUtil (Android) və DiffableDataSource (iOS) — avtomatik diff və animasiya ilə müasir təkamül
  • onBindViewHolder-da ağır əməliyyatlar, DiffUtil-ə məhəl qoymama və adapterdə resursların saxlanması — ümumi səhvlər
  • Adapter legacy kodun inteqrasiyası, formatların uyğunlaşdırılması və müxtəlif tətbiqlərin birləşdirilməsi üçün tətbiq edilir
  • Tövsiyə: siyahı yeniləmələrini əl ilə idarə etmək əvəzinə ListAdapter/DiffableDataSource istifadə edin

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun