Patrón Singleton
Parte de la sección Programación orientada a objetos del Journey de Swift de Coddy. Lección 42 de 57.
Un patrón de diseño es una solución probada para un problema de diseño común. El patrón singleton garantiza que una clase tenga exactamente una instancia, accesible desde cualquier lugar. En Swift, es un static let que contiene la instancia, además de un private init para que nadie pueda crear otra:
final class Settings {
static let shared = Settings()
var theme = "light"
private init() {}
}
Settings.shared.theme = "dark"
print(Settings.shared.theme)Salida:
darkCada uso de Settings.shared hace referencia al mismo objeto, por lo que un cambio realizado en una parte del programa es visible en todas partes. static let se crea de forma diferida en el primer uso y de manera segura incluso cuando varios hilos se inician al mismo tiempo:
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)Salida:
3
trueComo el inicializador es privado, Settings() no se compila fuera de la clase, lo que mantiene la promesa de «solo uno»:
// let other = Settings() // error: el inicializador de 'Settings' es inaccesible debido al nivel de protección 'private'Usa los singleton con moderación. Un singleton es un estado global: cualquier código puede cambiarlo y las pruebas no pueden empezar fácilmente con una copia limpia. Son adecuados para elementos que realmente deben existir una sola vez por programa, como un registrador o la configuración de la aplicación; pasar un objeto como parámetro suele ser más claro.
// más claro para probar: el logger se pasa
func process(order: Order, log: Logger) { log.write("processing \(order.id)") }Desafío
FácilCompleta el singleton Logger. Tiene una instancia static let shared, un inicializador privado, un array private(set) de entries y log(_:level:), que almacena [INFO] message o [ERROR] message (el nivel es info o error). errorCount es una propiedad calculada. El código proporcionado llama a Logger.shared desde dos funciones diferentes, por lo que ambas deben acceder a la misma instancia.
El código proporcionado lee líneas info,message o error,message, envía las líneas de información mediante handleInfo y las líneas de error mediante handleError, después imprime cada entrada y errors: 1.
Tu código debe ir en Logger.swift y Functions.swift. main.swift contiene el código de entrada/salida proporcionado y no se puede editar.
Pruébalo tú mismo
// Código de entrada/salida suministrado: déjalo 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)")
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesMétodos y selfInicializadoresLas clases son referenciasRepaso: tarjeta de biblioteca4Encapsulación
Control de accesoSolo lectura desde fueraProtección del estadoInicializadores que pueden fallarRepaso - Cuenta bancaria7Polimorfismo y genéricos
PolimorfismoConversión de tiposFunciones genéricasTipos genéricosRepaso - Calculadora de formas2Structs y tipos por valor
StructsSemántica de valoresMétodos mutablesStruct o claseRepaso - elemento del inventario5Herencia
SubclasesSobrescritura de métodosInicializadores y superfinal y jerarquíasRepaso: jerarquía de empleados8Protocolos estándar
CustomStringConvertibleEquatableComparableHashableRepaso - Ordenamiento personalizado11Proyecto: Gestión de bibliotecas
Libros y miembrosPréstamo de librosPractica por tu cuenta: Playground de Swift