Aula 163: Padrões de Design em Swift
Padrões de design são soluções reutilizáveis para problemas comuns que ocorrem no design de software. Nesta aula, exploraremos alguns dos padrões de design mais comumente usados em Swift, fornecendo exemplos para ilustrar o uso e a implementação de cada padrão.
1. Padrão Singleton
O padrão Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. Isso é útil quando um único objeto é necessário para coordenar ações em todo o sistema.
Exemplo:
class Singleton {
static let compartilhado = Singleton()
private init() {
// Inicialização privada para garantir que apenas uma instância seja criada.
}
func algumaFuncao() {
print("Função chamada na instância do Singleton.")
}
}
// Uso
let instanciaSingleton = Singleton.compartilhado
instanciaSingleton.algumaFuncao()
2. Padrão Observador
O padrão Observador permite que um objeto, conhecido como sujeito, mantenha uma lista de seus dependentes (observadores) e os notifique automaticamente sobre qualquer alteração de estado. Isso é particularmente útil na implementação da arquitetura Modelo-Visão-Controle (MVC).
Exemplo:
import Foundation
protocol Observador {
func atualizar()
}
class Sujeito {
private var observadores = [Observador]()
func adicionarObservador(_ observador: Observador) {
observadores.append(observador)
}
func removerObservador(_ observador: Observador) {
observadores.removeAll { $0 === observador }
}
func notificarObservadores() {
for observador in observadores {
observador.atualizar()
}
}
}
class ObservadorConcreto: Observador {
func atualizar() {
print("Observador foi notificado.")
}
}
// Uso
let sujeito = Sujeito()
let observador = ObservadorConcreto()
sujeito.adicionarObservador(observador)
sujeito.notificarObservadores()
3. Padrão Fábrica
O padrão Fábrica é usado para criar objetos sem especificar a classe exata do objeto que será criado. Ele ajuda a isolar a lógica de instância da lógica de negócio.
Exemplo:
protocol Animal {
func falar()
}
class Cachorro: Animal {
func falar() {
print("Au Au!")
}
}
class Gato: Animal {
func falar() {
print("Miau!")
}
}
class FabricaDeAnimais {
static func criarAnimal(tipo: String) -> Animal? {
switch tipo {
case "Cachorro":
return Cachorro()
case "Gato":
return Gato()
default:
return nil
}
}
}
// Uso
if let animal = FabricaDeAnimais.criarAnimal(tipo: "Cachorro") {
animal.falar() // Saída: Au Au!
}
4. Padrão Decorador
O padrão Decorador permite que comportamentos sejam adicionados a objetos individuais, seja de forma estática ou dinâmica, sem afetar o comportamento de outros objetos da mesma classe. Isso é útil para aderir ao Princípio Aberto/Fechado.
Exemplo:
protocol Cafe {
var custo: Double { get }
var descricao: String { get }
}
class CafeBasico: Cafe {
var custo: Double = 2.0
var descricao: String = "Café Básico"
}
class DecoradorDeLeite: Cafe {
private var cafe: Cafe
init(cafe: Cafe) {
self.cafe = cafe
}
var custo: Double {
return cafe.custo + 0.5
}
var descricao: String {
return cafe.descricao + ", Leite"
}
}
// Uso
let cafeSimples = CafeBasico()
print("\(cafeSimples.descricao): R$\(cafeSimples.custo)")
let cafeComLeite = DecoradorDeLeite(cafe: cafeSimples)
print("\(cafeComLeite.descricao): R$\(cafeComLeite.custo)")
5. Padrão Estratégia
O padrão Estratégia define uma família de algoritmos, encapsula cada um deles e os torna intercambiáveis. Esse padrão permite que o algoritmo varie independentemente dos clientes que o utilizam.
Exemplo:
protocol EstrategiaDeOrdenacao {
func ordenar(_ array: [Int]) -> [Int]
}
class OrdenacaoBolha: EstrategiaDeOrdenacao {
func ordenar(_ array: [Int]) -> [Int] {
var arrayOrdenado = array
for i in 0..<arrayOrdenado.count {
for j in 1..<arrayOrdenado.count - i {
if arrayOrdenado[j - 1] > arrayOrdenado[j] {
arrayOrdenado.swapAt(j - 1, j)
}
}
}
return arrayOrdenado
}
}
class OrdenacaoRapida: EstrategiaDeOrdenacao {
func ordenar(_ array: [Int]) -> [Int] {
guard array.count > 1 else { return array }
let pivô = array[array.count / 2]
let menor = array.filter { $0 < pivô }
let igual = array.filter { $0 == pivô }
let maior = array.filter { $0 > pivô }
return ordenar(menor) + igual + ordenar(maior)
}
}
class Ordenador {
var estrategia: EstrategiaDeOrdenacao
init(estrategia: EstrategiaDeOrdenacao) {
self.estrategia = estrategia
}
func ordenar(array: [Int]) -> [Int] {
return estrategia.ordenar(array)
}
}
// Uso
let array = [3, 5, 1, 4, 2]
let ordenador = Ordenador(estrategia: OrdenacaoBolha())
let arrayOrdenado = ordenador.ordenar(array: array)
print(arrayOrdenado) // Saída do resultado da Ordenação por Bolha
Conclusão
Os padrões de design são uma ferramenta poderosa que pode ajudá-lo a escrever um código mais manutenível, flexível e reutilizável. Os padrões descritos nesta aula, incluindo Singleton, Observador, Fábrica, Decorador e Estratégia, são apenas alguns dos muitos padrões disponíveis. Familiarizar-se com esses padrões é um passo valioso para se tornar um desenvolvedor Swift proficiente.