Singleton — apa itu, instance tunggal kelas di iOS dan Android

Penulis: IT Sectr Diterbitkan: 2026-02-17 Waktu membaca: 8 mnt

Singleton — pola konstruktif yang menjamin instance tunggal kelas dan menyediakan titik akses global ke sana. Singleton banyak digunakan dalam pengembangan mobile untuk sumber daya bersama: klien jaringan, basis data, manajer pengaturan. Pola ini dijelaskan dalam buku klasik GoF (1994) dan tetap menjadi salah satu yang paling dikenal. Selengkapnya — di Refactoring Guru: Singleton.

Poin Penting

  • Singleton — menjamin satu instance kelas di seluruh aplikasi
  • Titik akses global — properti statis shared atau companion object
  • Thread safety — memerlukan sinkronisasi untuk kerja yang benar di lingkungan multi-thread
  • Kritik — Singleton mempersulit pengujian dan menciptakan dependensi tersembunyi
  • Alternatif — Dependency Injection, Service Locator untuk mengganti Singleton

Apa itu Singleton: esensi pola singleton?

Singleton — pola desain konstruktif yang dijelaskan oleh GoF (Gang of Four) pada tahun 1994. Pola ini memecahkan dua tugas: membatasi pembuatan instance kelas menjadi satu objek dan menyediakan akses global ke objek tersebut. Singleton berguna untuk sumber daya yang harus unik: pabrik sesi, cache gambar, manajer koneksi basis data, klien Crashlytics atau Analytics.

Implementasi Singleton memerlukan konstruktor privat (melarang pembuatan eksternal), bidang statis dengan instance tunggal, dan metode akses statis (shared, instance, getInstance). Klien memanggil Singleton.shared.method() tanpa khawatir tentang pembuatan objek. Pola ini populer di iOS dan Android: URLSession.shared, UserDefaults.standard, FirebaseApp.sharedInstance — semuanya adalah Singleton. Namun penggunaan Singleton yang berlebihan mengarah ke anti-pola Global State.

Masalah Singleton — dependensi tersembunyi (kelas secara implisit bergantung pada objek Singleton), kesulitan pengujian (tidak dapat mengganti instance dalam pengujian tanpa upaya tambahan), pelanggaran Single Responsibility Principle (Singleton mengelola instance-nya sendiri dan logika bisnis). Pengembangan mobile modern lebih memilih DI (Dagger, Hilt, Swinject) untuk mengelola instance tunggal — kontainer DI membuat objek sekali dan menyuntikkannya melalui konstruktor.

Singleton di iOS dengan Swift: shared dan properti statis

Swift Singleton diimplementasikan melalui properti statis shared dengan inisialisasi privat. Sejak Swift 3, inisialisasi malas properti statis dijamin thread-safe — kompiler secara otomatis menambahkan sinkronisasi melalui dispatch_once. Cukup mendeklarasikan static let shared = Class() dan membuat init() privat. Swift tidak memerlukan sinkronisasi tambahan untuk akses single-thread setelah inisialisasi.

swift
final class NetworkManager {
    // Thread-safe Singleton
    static let shared = NetworkManager()

    private init() {
        URLSessionConfiguration.default.timeoutIntervalForRequest = 30
    }

    private var cache = NSCache<NSString, NSData>()

    func fetchData(from url: URL) async throws -> Data {
        let key = url.absoluteString as NSString
        if let cached = cache.object(forKey: key) {
            return cached as Data
        }
        let (data, _) = try await URLSession.shared.data(from: url)
        cache.setObject(data as NSData, forKey: key)
        return data
    }
}

// Penggunaan
let data = try await NetworkManager.shared.fetchData(from: url)

Apple Singleton — di iOS SDK banyak objek menggunakan Singleton: UIApplication.shared, UIScreen.main, FileManager.default, NotificationCenter.default, UserDefaults.standard. Apple menggunakan Singleton untuk layanan yang secara fisik unik (satu layar, satu aplikasi). Pengembang menyalin pola ini untuk layanan mereka. Di SwiftUI akses global ke Singleton digantikan oleh Environment dan @EnvironmentObject, yang meningkatkan testabilitas.

Singleton di Android dengan Kotlin: companion object dan object

Kotlin Singleton — cara paling sederhana: kata kunci object mendeklarasikan kelas-singleton dengan inisialisasi malas pada akses pertama. Kotlin object thread-safe dan tidak memerlukan sinkronisasi tambahan. Jika Singleton dengan parameter konstruktor diperlukan, companion object dengan delegasi lazy digunakan. Di Android Singleton sering diperlukan untuk konteks Application dan layanan yang diinisialisasi melalui Application.onCreate().

kotlin
// Opsi 1: object — Singleton sederhana tanpa parameter
object AppPreferences {
    private val prefs = Application.instance
        .getSharedPreferences("app", Context.MODE_PRIVATE)

    var isFirstLaunch: Boolean
        get() = prefs.getBoolean("first_launch", true)
        set(value) = prefs.edit { putBoolean("first_launch", value) }
}

// Opsi 2: companion object — Singleton dengan parameter
class ApiClient private constructor(baseUrl: String) {
    companion object {
        @Volatile
        private var instance: ApiClient? = null

        fun getInstance(baseUrl: String): ApiClient {
            return instance ?: this.synchronized {
                instance ?: ApiClient(baseUrl).also { instance = it }
            }
        }
    }

    fun request(endpoint: String): String { /* ... */ }
}

Android SDK Singleton — banyak layanan sistem Android mengimplementasikan Singleton: context.getSystemService(), Room.databaseBuilder(), Retrofit.Builder(). Contohnya termasuk SharedPreferences, MediaPlayer, AudioManager. Di aplikasi Android Singleton sering digunakan untuk repositori, manajer, dan pabrik. Google merekomendasikan mengganti Singleton dengan DI (Hilt, Koin), di mana lingkup Singleton (Scope.Singleton atau @Singleton) dikelola oleh kontainer, dan kelas tetap testable.

Thread safety: dispatch_once, synchronized dan lock

Thread safety — persyaratan kritis untuk Singleton di lingkungan multi-thread. Tanpa sinkronisasi, dua thread dapat secara bersamaan memeriksa instance == null dan membuat dua instance. Solusinya — penguncian saat pembuatan pertama dan pelepasan setelah inisialisasi. Di Swift properti statis (static let) secara default thread-safe. Di Kotlin object thread-safe. Untuk gaya Java di Kotlin digunakan synchronized atau @Volatile + double-check locking.

BahasaMekanismeThread safetyInisialisasi malas
Swiftstatic letdispatch_once (otomatis)Ya, pada akses pertama
Kotlin objectObject declarationInisialisator kelas thread-safeYa, pada akses pertama
Kotlin companionsynchronized + @VolatileDouble-checked lockingYa, melalui lazy atau synchronized
Javasynchronized + volatileDouble-checked lockingYa, di getInstance()

Double-checked locking — pola untuk inisialisasi malas Singleton. Pemeriksaan pertama tanpa sinkronisasi (cepat, jika instance sudah dibuat), kedua — di dalam synchronized (pembuatan hanya oleh satu thread). @Volatile menjamin visibilitas perubahan untuk semua thread. Tanpa volatile thread lain mungkin melihat objek yang dibuat sebagian. Di Kotlin delegasi lazy dengan LazyThreadSafetyMode.SYNCHRONIZED secara otomatis mengimplementasikan double-checked locking.

Singleton vs Dependency Injection: kapan menggunakan

Dependency Injection — alternatif Singleton untuk mengelola instance tunggal. Kontainer DI (Dagger, Hilt, Koin, Swinject) membuat objek sekali dalam lingkup Singleton dan menyuntikkannya melalui konstruktor. Kelas tidak tahu tentang status Singleton-nya — ini diputuskan oleh kontainer. Kode menjadi testable: dalam pengujian modul DI diganti dengan modul mock. Kelebihan DI: dependensi eksplisit di konstruktor, kemungkinan penggantian, siklus hidup terpadu.

Kapan Singleton dibenarkan — objek tingkat sistem: Crashlytics, Analytics, Logging. Layanan ini diinisialisasi sekali di AppDelegate/Application dan digunakan di mana-mana. DI berlebihan untuk mereka. Singleton juga nyaman untuk cache gambar (NSCache, Coil, Glide), di mana akses global dibenarkan oleh kinerja. Untuk yang lainnya DI lebih disukai: membuat dependensi terlihat, menyederhanakan pengujian dan refactoring.

Pendekatan hibrida — Singleton dengan kemampuan penggantian untuk pengujian. Di Swift digunakan protokol + properti statis yang dapat diganti oleh pengujian (misalnya melalui URLProtocol untuk URLSession). Di Kotlin — kelas terbuka dengan properti injectable, di mana pengujian mengatur mock melalui refleksi atau setter. Pendekatan ini mempertahankan kesederhanaan Singleton, tetapi memberikan alat untuk pengujian. Google merekomendasikan Hilt untuk Android, Apple tidak memaksakan DI untuk iOS — pilihan tergantung pada tim.

Pertanyaan yang Sering Diajukan

Apakah Singleton itu anti-pola?

Tidak, Singleton adalah pola GoF, tetapi penggunaannya yang sering salah mengubahnya menjadi anti-pola Global State. Singleton dibenarkan untuk sumber daya yang secara fisik unik (layar, printer, sistem file). Masalah muncul ketika Singleton digunakan untuk mengelola data: dependensi tersembunyi, kesulitan pengujian, pelanggaran Single Responsibility Principle. Alternatif modern — DI dengan lingkup Singleton.

Bagaimana cara menguji kode yang menggunakan Singleton?

Tiga pendekatan: (1) melalui protokol — Singleton mengimplementasikan protokol, pengujian mengganti implementasi; (2) melalui DI — Singleton disuntikkan sebagai dependensi melalui konstruktor; (3) melalui metode reset — Singleton memiliki metode untuk mereset status dalam pengujian (hanya untuk build pengujian). Pendekatan pertama lebih disukai, ketiga — berbahaya untuk production. Swift memungkinkan mengganti properti shared melalui manipulasi runtime dalam pengujian.

Apa perbedaan Kotlin object dengan Java Singleton?

Kotlin object — konstruksi bahasa yang membuat Singleton di tingkat bytecode. Berbeda dengan implementasi Java dengan konstruktor privat dan getInstance(), object menjamin thread safety, inisialisasi malas, dan larangan pewarisan. Java Singleton memerlukan sinkronisasi manual (synchronized) dan volatile untuk kerja yang benar di lingkungan multi-thread. Kotlin object — cara teraman dan paling ringkas di Android.

Bisakah Singleton diwariskan?

Pewarisan Singleton melanggar pola: jika kelas Singleton dapat diwariskan, subkelas dapat membuat instance kedua, melanggar keunikan. Di Swift final class melarang pewarisan. Kotlin object tidak dapat diwariskan (object — sealed). Jika Singleton dengan variasi diperlukan, gunakan kontainer DI dengan lingkup Singleton: menjamin satu instance dan mendukung pewarisan melalui antarmuka.

Bagaimana cara meneruskan parameter ke Singleton di Android?

Parameter diteruskan melalui init(context: Application) atau getInstance(param). Kotlin object tidak menerima parameter — gunakan companion object dengan metode pabrik getInstance(param). Hilt memecahkan masalah: @Singleton + @Inject constructor(context: Application) — kontainer DI menyuntikkan konteks Application secara otomatis. Untuk klien retrofit parameter (baseUrl, interceptors) diteruskan melalui builder di modul DI.

Ringkasan

  • Singleton — pola dengan instance tunggal dan akses global
  • Swift shared — static let dengan thread safety dari kompiler
  • Kotlin object — inisialisasi malas tanpa kode tambahan
  • Thread safety — double-checked locking untuk Java, otomatis untuk Swift/Kotlin
  • Apple SDK — UIApplication.shared, UserDefaults.standard, FileManager.default
  • Android SDK — Retrofit, Room, SharedPreferences melalui manajer Singleton
  • Alternatif — Dependency Injection untuk kode yang testable

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga