Menu
Coddy logo textTech

Patron Singleton

Fait partie de la section Programmation orientée objet du Journey Swift de Coddy. Leçon 42 sur 57.

Un motif de conception est une solution éprouvée à un problème de conception courant. Le motif singleton garantit qu’une classe possède exactement une instance, accessible depuis n’importe où. En Swift, il s’agit d’un static let contenant l’instance, ainsi que d’un private init afin que personne ne puisse en créer une autre :

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

    private init() {}
}

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

Sortie :

dark

Chaque utilisation de Settings.shared fait référence au même objet, de sorte qu’une modification effectuée dans une partie du programme est visible partout. static let est créé lors de la première utilisation et de manière sûre, même lorsque plusieurs threads démarrent simultanément :

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)

Sortie :

3
true

Comme l’initialiseur est privé, Settings() ne se compile pas en dehors de la classe, ce qui tient la promesse « un seul » :

// let other = Settings()   // erreur : l'initialiseur de 'Settings' est inaccessible en raison du niveau de protection 'private'

Utilisez les singletons avec parcimonie. Un singleton est un état global : n’importe quel code peut le modifier, et les tests ne peuvent pas facilement démarrer avec une copie vierge. Ils conviennent aux éléments qui sont véritablement uniques par programme, comme un logger ou la configuration de l’application ; passer un objet en paramètre est souvent plus clair.

// plus clair pour tester : le logger est passé en paramètre
func process(order: Order, log: Logger) { log.write("processing \(order.id)") }
challenge icon

Défi

Facile

Complétez le singleton Logger. Il possède une instance static let shared, un initialiseur privé, un tableau private(set) de entries, ainsi que log(_:level:), qui stocke [INFO] message ou [ERROR] message (le niveau est info ou error). errorCount est une propriété calculée. Le code fourni appelle Logger.shared depuis deux fonctions différentes ; elles doivent donc toutes deux accéder à la même instance.

Le code fourni lit des lignes info,message ou error,message, transmet les lignes d’information à handleInfo et les lignes d’erreur à handleError, puis affiche chaque entrée ainsi que errors: 1.

Votre code doit être placé dans Logger.swift et Functions.swift. main.swift contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

// Code d'entrée/sortie fourni : le garder tel quel
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 iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Playground Swift