Sobes.tech
Middle+

Zašto se Singleton obrazac smatra anti-obrazcem?

sobes.tech АИ

Одговор од АИ

Singleton krši SOLID principe i otežava testiranje:

  • Kršenje principa jedinstvene odgovornosti (SRP): Klasa istovremeno odgovara za svoju logiku i za upravljanje svojim životnim ciklusom (kreiranje i pristup jedinstvenom primeru).
  • Kršenje principa otvorenosti/zatvorenosti (OCP): Proširenje funkcionalnosti Singleton klase može biti otežano bez izmene njenog koda.
  • Kršenje principa zamene Barbare Liskov (LSP): Podtipovi Singleton klase možda neće zadovoljiti ugovore osnovnog tipa zbog specifičnosti implementacije Singleton.
  • Kršenje principa inverzije zavisnosti (DIP): Moduli zavise od konkretne implementacije Singleton, a ne od apstrakcija. To otežava zamenjivanje Singleton objekta sa mock ili stub za testiranje.
  • Problemi sa testiranjem: Singleton instanca je globalno stanje, što otežava paralelno izvršavanje testova i izolaciju test scenarija. Teško je zameniti zavisnost od Singleton objekta.
  • Skrivena zavisnost: Korišćenje Singleton skriva zavisnosti između modula, jer one nisu eksplicitno prosleđene.
  • Problemi sa višestrukim nitima: Potreba za sinhronizacijom pristupa Singleton instanci u višedretvenom okruženju može dovesti do komplikacija u kodu i potencijalnih grešaka.
  • Složenost u odlaganju: Upravljanje životnim ciklusom Singleton objekta i njegovo odlaganje može biti nejasno.

Umesto Singleton često je poželjno koristiti ubrizgavanje zavisnosti (Dependency Injection) ili Service Locator za upravljanje životnim ciklusom objekata i njihovim pristupom.

Primer tipične implementacije Singleton na Swift-u, koji demonstrira pomenute probleme:

// Singleton.swift
class DataManager {
    static let shared = DataManager() // Globalna tačka pristupa, skriva zavisnost
    
    private init() { // Zatvoren i inicijalizator, otežava kreiranje mock objekata
        // Inicijalizacija resursa ili stanja
    }
    
    func fetchData() -> [String] {
        // Logika za dobijanje podataka (npr. iz mreže ili baze podataka)
        // Ova logika je povezana sa upravljanjem stanjem i pristupom, krši SRP
        return ["Item 1", "Item 2"]
    }
}

// Primer korišćenja
// Modul koji direktno zavisi od DataManager.shared
class ViewController {
    func displayData() {
        let data = DataManager.shared.fetchData() // Skrivena zavisnost
        print(data)
    }
}

// Testiranje ViewController-a postaje složenije:
// Kako zameniti DataManager.shared sa mock objektom?
// Kako izolovati testove ako je DataSourceManager.shared globalni?