Menu
Coddy logo textTech

Singleton Kalıbı

Coddy'nin Swift Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 42 / 57.

Tasarım kalıbı, yaygın bir tasarım problemine yönelik kanıtlanmış bir çözümdür. Singleton kalıbı, bir sınıfın tam olarak bir örneğe sahip olmasını ve bu örneğe her yerden erişilebilmesini sağlar. Swift'te bu, örneği tutan bir static let ile birlikte, hiç kimsenin başka bir örnek oluşturamaması için bir private init kullanılarak gerçekleştirilir:

final class Settings {
    static let shared = Settings()
    var theme = "light"

    private init() {}
}

Settings.shared.theme = "dark"
print(Settings.shared.theme)

Çıktı:

dark

Settings.shared öğesinin her kullanımı aynı nesneye başvurur; bu nedenle programın bir bölümünde yapılan değişiklik her yerde görünür. static let ilk kullanımda tembel olarak oluşturulur ve birkaç iş parçacığı aynı anda başlasa bile güvenlidir:

final class Counter {
    static let shared = Counter()
    private(set) var hits = 0
    private init() {}
    func hit() { hits += 1 }
}

func pageA() { Counter.shared.hit() }
func pageB() { Counter.shared.hit(); Counter.shared.hit() }
pageA()
pageB()
print(Counter.shared.hits)
print(Counter.shared === Counter.shared)

Çıktı:

3
true

Başlatıcı private olduğu için Settings() sınıfın dışında derlenmez; bu da “yalnızca bir tane” sözünü yerine getirir:

// let other = Settings()   // hata: 'Settings' başlatıcısı 'private' koruma seviyesi nedeniyle erişilemez

Singleton’ları ölçülü kullanın. Singleton, global durumdur: herhangi bir kod onu değiştirebilir ve testler temiz bir kopyayla başlatılamaz. Logger veya uygulamanın yapılandırması gibi program başına gerçekten tek olan şeyler için uygundurlar; bir nesneyi parametre olarak geçirmek genellikle daha açıktır.

// test için daha net: logger içeriye geçirilir
func process(order: Order, log: Logger) { log.write("processing \(order.id)") }
challenge icon

Görev

Kolay

Logger singleton'ını tamamla. Bir static let shared örneği, private bir başlatıcı, entries değerlerinden oluşan bir private(set) dizisi ve log(_:level:) işlevi vardır; bu işlev [INFO] message veya [ERROR] message değerlerini depolar (level, info ya da error olur). errorCount hesaplanan bir özelliktir. Sağlanan kod, iki farklı işlevden Logger.shared'ı çağırır; bu nedenle her ikisi de aynı örneğe ulaşmalıdır.

Sağlanan kod, info,message veya error,message biçimindeki satırları okur, info satırlarını handleInfo üzerinden ve error satırlarını handleError üzerinden gönderir, ardından her girdiyi ve errors: 1 değerini yazdırır.

Kodun Logger.swift ve Functions.swift dosyalarına yazılmalıdır. main.swift, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

// Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
    let p = line.split(separator: ",", maxSplits: 1).map(String.init)
    if p[0] == "error" { handleError(p[1]) } else { handleInfo(p[1]) }
}
for e in Logger.shared.entries { print(e) }
print("errors: \(Logger.shared.errorCount)")
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Swift playground