Singleton — ano ito, nag-iisang instance ng klase sa iOS at Android

May-akda: IT Sectr Nai-publish: 2026-02-17 Oras ng pagbabasa: 8 min

Singleton — pattern ng pagbuo na ginagarantiya ang nag-iisang instance ng klase at nagbibigay ng pandaigdigang access point dito. Singleton ay malawakang ginagamit sa mobile development para sa mga shared na mapagkukunan: mga network client, database, manager ng setting. Ang pattern ay inilarawan sa klasikong aklat na GoF (1994) at nananatiling isa sa pinakakilala. Higit pa — sa Refactoring Guru: Singleton.

Pangunahin

  • Singleton — ginagarantiya ang isang instance ng klase sa buong app
  • Pandaigdigang access point — static na property na shared o companion object
  • Thread safety — nangangailangan ng synchronization para sa tamang trabaho sa multi-thread na kapaligiran
  • Kritika — pinapahirap ng Singleton ang pag-test at lumilikha ng mga nakatagong dependency
  • Mga Alternatibo — Dependency Injection, Service Locator para palitan ang Singleton

Ano ang Singleton: kakanyahan ng pattern na singleton?

Singleton — pattern ng pagbuo na inilarawan ng GoF (Gang of Four) noong 1994. Ang pattern ay lumulutas ng dalawang gawain: nililimitahan ang paglikha ng instance ng klase sa isang bagay at nagbibigay ng pandaigdigang access sa bagay na ito. Ang Singleton ay kapaki-pakinabang para sa mga mapagkukunan na dapat ay natatangi: pabrika ng session, cache ng imahe, manager ng koneksyon sa database, Crashlytics o Analytics client.

Implementasyon ng Singleton ay nangangailangan ng pribadong constructor (nagbabawal ng panlabas na paglikha), static na field na may nag-iisang instance at static na paraan ng access (shared, instance, getInstance). Ang mga kliyente ay tumatawag ng Singleton.shared.method() nang hindi nag-aalala tungkol sa paglikha ng bagay. Ang pattern ay popular sa iOS at Android: URLSession.shared, UserDefaults.standard, FirebaseApp.sharedInstance — lahat ito ay Singleton. Gayunpaman, ang labis na paggamit ng Singleton ay humahantong sa anti-pattern na Global State.

Mga Problema ng Singleton — mga nakatagong dependency (mga klase ay implicit na umaasa sa bagay na Singleton), hirap sa pag-test (hindi mapapalitan ang instance sa test nang walang karagdagang pagsisikap), paglabag sa Single Responsibility Principle (Singleton namamahala pareho ng sarili nitong instance at ng business logic). Ang modernong mobile development ay mas pinipili ang DI (Dagger, Hilt, Swinject) para sa pamamahala ng mga nag-iisang instance — ang DI container ay lumilikha ng bagay nang isang beses at ini-inject ito sa pamamagitan ng constructor.

Singleton sa iOS sa Swift: shared at static na mga property

Swift Singleton ay implementado sa pamamagitan ng static na property na shared na may pribadong initializer. Mula noong Swift 3, ang lazy initialization ng static na mga property ay garantisadong thread-safe — awtomatikong nagdaragdag ang compiler ng synchronization sa pamamagitan ng dispatch_once. Sapat na ideklara ang static let shared = Class() at gawing pribado ang init(). Hindi nangangailangan ang Swift ng karagdagang synchronization para sa single-thread na access pagkatapos ng initialization.

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

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

Apple Singleton — sa iOS SDK maraming bagay ang gumagamit ng Singleton: UIApplication.shared, UIScreen.main, FileManager.default, NotificationCenter.default, UserDefaults.standard. Ginagamit ng Apple ang Singleton para sa mga serbisyong pisikal na natatangi (isang screen, isang app). Kinokopya ng mga developer ang pattern na ito para sa kanilang mga serbisyo. Sa SwiftUI ang pandaigdigang access sa Singleton ay pinapalitan ng Environment at @EnvironmentObject, na nagpapabuti sa testability.

Singleton sa Android sa Kotlin: companion object at object

Kotlin Singleton — ang pinakasimpleng paraan: ang keyword na object ay nagdedeklara ng klase-singleton na may lazy initialization sa unang pag-access. Ang Kotlin object ay thread-safe at hindi nangangailangan ng karagdagang synchronization. Kung kailangan ang Singleton na may mga parameter ng constructor, ginagamit ang companion object na may lazy delegate. Sa Android ang Singleton ay madalas na kinakailangan para sa konteksto ng Application at mga serbisyong na-initialize sa pamamagitan ng Application.onCreate().

kotlin
// Opsyon 1: object — simpleng Singleton walang 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) }
}

// Opsyon 2: companion object — Singleton na may mga 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 — maraming system service ng Android ang nag-iimplementa ng Singleton: context.getSystemService(), Room.databaseBuilder(), Retrofit.Builder(). Kabilang sa mga halimbawa ang SharedPreferences, MediaPlayer, AudioManager. Sa mga Android app ang Singleton ay madalas na ginagamit para sa mga repository, manager at pabrika. Inirerekomenda ng Google na palitan ang Singleton ng DI (Hilt, Koin), kung saan ang Singleton scope (Scope.Singleton o @Singleton) ay pinamamahalaan ng container, at ang klase ay nananatiling testable.

Thread safety: dispatch_once, synchronized at lock

Thread safety — kritikal na pangangailangan para sa Singleton sa multi-thread na kapaligiran. Kung walang synchronization, dalawang thread ay maaaring sabay na suriin ang instance == null at lumikha ng dalawang instance. Solusyon — pag-lock sa unang paglikha at pag-release pagkatapos ng initialization. Sa Swift static na mga property (static let) ay thread-safe bilang default. Sa Kotlin ang object ay thread-safe. Para sa Java-style sa Kotlin ginagamit ang synchronized o @Volatile + double-check locking.

WikaMekanismoThread safetyLazy initialization
Swiftstatic letdispatch_once (awtomatiko)Oo, sa unang pag-access
Kotlin objectObject declarationInitializer ng klase ay thread-safeOo, sa unang pag-access
Kotlin companionsynchronized + @VolatileDouble-checked lockingOo, sa pamamagitan ng lazy o synchronized
Javasynchronized + volatileDouble-checked lockingOo, sa getInstance()

Double-checked locking — pattern para sa lazy initialization ng Singleton. Unang pagsusuri nang walang synchronization (mabilis, kung ang instance ay nagawa na), pangalawa — sa loob ng synchronized (paglikha lamang ng isang thread). @Volatile ginagarantiya ang visibility ng mga pagbabago para sa lahat ng thread. Kung walang volatile, ang ibang thread ay maaaring makakita ng bahagyang nagawang bagay. Sa Kotlin ang lazy delegate na may LazyThreadSafetyMode.SYNCHRONIZED ay awtomatikong nag-iimplementa ng double-checked locking.

Singleton vs Dependency Injection: kailan gagamitin

Dependency Injection — alternatibo sa Singleton para sa pamamahala ng nag-iisang instance. Ang DI container (Dagger, Hilt, Koin, Swinject) ay lumilikha ng bagay nang isang beses sa Singleton scope at ini-inject ito sa pamamagitan ng constructor. Hindi alam ng klase ang tungkol sa katayuan nitong Singleton — ito ay pinagpapasyahan ng container. Ang code ay nagiging testable: sa test ang DI module ay pinapalitan ng mock module. Mga bentahe ng DI: malinaw na dependency sa constructor, posibilidad ng override, pinag-isang lifecycle.

Kailan makatwiran ang Singleton — mga bagay sa antas ng system: Crashlytics, Analytics, Logging. Ang mga serbisyong ito ay ini-initialize nang isang beses sa AppDelegate/Application at ginagamit sa lahat ng dako. Ang DI ay labis para sa kanila. Ang Singleton ay maginhawa rin para sa mga cache ng imahe (NSCache, Coil, Glide), kung saan ang pandaigdigang access ay makatwiran sa pagganap. Para sa lahat ng iba pa ang DI ay mas gusto: ginagawang nakikita ang mga dependency, pinapasimple ang pag-test at refactoring.

Hybrid na diskarte — Singleton na may kakayahang mag-override para sa mga test. Sa Swift ginagamit ang isang protocol + static na property na mapapalitan ng test (halimbawa, sa pamamagitan ng URLProtocol para sa URLSession). Sa Kotlin — open class na may injectable na property, kung saan ang test ay nagtatakda ng mock sa pamamagitan ng reflection o setter. Ang ganitong diskarte ay nagpapanatili ng pagiging simple ng Singleton, ngunit nagbibigay ng mga kasangkapan para sa pag-test. Inirerekomenda ng Google ang Hilt para sa Android, hindi ipinapatupad ng Apple ang DI para sa iOS — ang pagpili ay depende sa koponan.

Mga Madalas Itanong

Ang Singleton ba ay anti-pattern?

Hindi, ang Singleton ay pattern ng GoF, ngunit ang madalas nitong maling paggamit ay ginagawa itong anti-pattern na Global State. Ang Singleton ay makatwiran para sa pisikal na natatanging mga mapagkukunan (screen, printer, file system). Ang mga problema ay lumitaw kapag ang Singleton ay ginagamit para sa pamamahala ng data: mga nakatagong dependency, hirap sa pag-test, paglabag sa Single Responsibility Principle. Modernong alternatibo — DI na may Singleton scope.

Paano i-test ang code na gumagamit ng Singleton?

Tatlong diskarte: (1) sa pamamagitan ng protocol — nag-iimplementa ang Singleton ng protocol, pinapalitan ng mga test ang implementasyon; (2) sa pamamagitan ng DI — ang Singleton ay ini-inject bilang dependency sa pamamagitan ng constructor; (3) sa pamamagitan ng reset method — ang Singleton ay may paraan para i-reset ang estado sa mga test (para lamang sa test build). Ang unang diskarte ay mas gusto, ang pangatlo — mapanganib para sa production. Pinapayagan ng Swift na palitan ang shared property sa pamamagitan ng runtime manipulations sa mga test.

Paano naiiba ang Kotlin object sa Java Singleton?

Ang Kotlin object — konstruksyon ng wika na lumilikha ng Singleton sa antas ng bytecode. Hindi tulad ng Java implementasyon na may pribadong constructor at getInstance(), ang object ay ginagarantiya ang thread safety, lazy initialization at pagbabawal ng pamana. Ang Java Singleton ay nangangailangan ng manu-manong synchronization (synchronized) at volatile para sa tamang trabaho sa multi-thread na kapaligiran. Ang Kotlin object — ang pinakaligtas at pinakakompormeng paraan sa Android.

Maaari bang manahin ang Singleton?

Ang pamana ng Singleton ay lumalabag sa pattern: kung ang klase ng Singleton ay maaaring manahin, ang subclass ay maaaring lumikha ng pangalawang instance, na lumalabag sa pagiging natatangi. Sa Swift ang final class ay nagbabawal ng pamana. Ang Kotlin object ay hindi maaaring manahin (ang object ay sealed). Kung kailangan ang Singleton na may pagkakaiba-iba, gamitin ang DI container na may Singleton scope: ginagarantiya nito ang isang instance at sumusuporta sa pamana sa pamamagitan ng mga interface.

Paano magpasa ng mga parameter sa Singleton sa Android?

Ang mga parameter ay ipinapasa sa pamamagitan ng init(context: Application) o getInstance(param). Ang Kotlin object ay hindi tumatanggap ng mga parameter — gumamit ng companion object na may factory method na getInstance(param). Nilulutas ng Hilt ang problema: @Singleton + @Inject constructor(context: Application) — awtomatikong ini-inject ng DI container ang konteksto ng Application. Para sa retrofit client ang mga parameter (baseUrl, interceptors) ay ipinapasa sa pamamagitan ng builder sa DI module.

Buod

  • Singleton — pattern na may nag-iisang instance at pandaigdigang access
  • Swift shared — static let na may thread safety mula sa compiler
  • Kotlin object — lazy initialization nang walang karagdagang code
  • Thread safety — double-checked locking para sa Java, awtomatiko para sa Swift/Kotlin
  • Apple SDK — UIApplication.shared, UserDefaults.standard, FileManager.default
  • Android SDK — Retrofit, Room, SharedPreferences sa pamamagitan ng Singleton manager
  • Mga Alternatibo — Dependency Injection para sa testable na code

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din