Menu
Coddy logo textTech

Padrão Singleton

Parte da seção Programação Orientada a Objetos do Journey de Swift da Coddy. Lição 42 de 57.

Um padrão de projeto é uma solução comprovada para um problema comum de projeto. O padrão singleton garante que uma classe tenha exatamente uma instância, acessível de qualquer lugar. Em Swift, ele é um static let que contém a instância, além de um private init para que ninguém possa criar outra:

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

    private init() {}
}

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

Saída:

dark

Cada uso de Settings.shared refere-se ao mesmo objeto, portanto uma alteração feita em uma parte do programa fica visível em todos os lugares. static let é criado sob demanda no primeiro uso e com segurança mesmo quando várias threads são iniciadas ao mesmo tempo:

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)

Saída:

3
true

Como o inicializador é privado, Settings() não compila fora da classe, o que mantém a promessa de "apenas uma":

// let other = Settings()   // erro: o inicializador de 'Settings' é inacessível devido ao nível de proteção 'private'

Use singletons com moderação. Um singleton é um estado global: qualquer código pode alterá-lo, e os testes não podem começar facilmente a partir de uma cópia limpa. Eles são adequados para coisas que realmente existem uma por programa, como um logger ou a configuração do app; passar um objeto como parâmetro costuma ser mais claro.

// mais claro para testar: o logger é passado
func process(order: Order, log: Logger) { log.write("processing \(order.id)") }
challenge icon

Desafio

Fácil

Complete o singleton Logger. Ele tem uma instância static let shared, um inicializador privado, um array private(set) de entries e log(_:level:), que armazena [INFO] message ou [ERROR] message (o nível é info ou error). errorCount é uma propriedade computada. O código fornecido chama Logger.shared a partir de duas funções diferentes, portanto ambas devem acessar a mesma instância.

O código fornecido lê linhas info,message ou error,message, envia as linhas de informação por meio de handleInfo e as linhas de erro por meio de handleError e, em seguida, imprime cada entrada e errors: 1.

Seu código deve ficar em Logger.swift e Functions.swift. main.swift contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

// Código de entrada/saída fornecido: mantenha-o como está
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 iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Swift