Padrões de Projeto em Swift: dos fundamentos à prática
Padrões de Projeto (Design Patterns) são soluções comprovadas para problemas típicos de desenvolvimento. No mundo Swift e no ecossistema Apple (iOS/macOS), conhecê-los torna-se obrigatório para criar código sustentável, testável e escalável. Neste artigo, analisaremos os principais padrões, dividindo-os em três categorias principais: criacionais, estruturais e comportamentais. Cada padrão será ilustrado com um exemplo funcional em Swift.
Padrões Criacionais: Singleton, Factory Method e Builder
Os padrões criacionais são responsáveis pelo processo de criação de objetos, tornando-o mais flexível e independente do código cliente.
Singleton (Instância Única)
Garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. No iOS, é frequentemente usado para gerenciar sessões de rede, bancos de dados (Core Data) ou configurações do aplicativo.
class NetworkManager { static let shared = NetworkManager() private init() {} func fetchData(from url: URL) { // Lógica da requisição print("Fetching data from \\(url)") }}
// UsoNetworkManager.shared.fetchData(from: URL(string: "https://example.com")!)Factory Method (Método Fábrica)
Define uma interface para criar um objeto, mas permite que as subclasses alterem o tipo do objeto criado. É ideal para criar componentes de UI dependendo da versão do iOS ou da configuração.
protocol Button { func render()}
class iOSButton: Button { func render() { print("Rendering iOS button") }}
class macOSButton: Button { func render() { print("Rendering macOS button") }}
enum Platform { case iOS, macOS }
class ButtonFactory { static func createButton(for platform: Platform) -> Button { switch platform { case .iOS: return iOSButton() case .macOS: return macOSButton() } }}
// Usolet button = ButtonFactory.createButton(for: .iOS)button.render()Builder (Construtor)
Permite criar objetos complexos passo a passo. É amplamente usado para configurar requisições (URLRequest) ou configurações complexas de UI.
class Pizza { var dough: String = "" var cheese: String = "" var toppings: [String] = []}
class PizzaBuilder { private var pizza = Pizza() func setDough(_ dough: String) -> PizzaBuilder { pizza.dough = dough return self } func setCheese(_ cheese: String) -> PizzaBuilder { pizza.cheese = cheese return self } func addTopping(_ topping: String) -> PizzaBuilder { pizza.toppings.append(topping) return self } func build() -> Pizza { return pizza }}
// Usolet margherita = PizzaBuilder() .setDough("Thin") .setCheese("Mozzarella") .addTopping("Basil") .build()Padrões Estruturais: Adapter, Decorator e Facade
Os padrões estruturais simplificam o design definindo maneiras de combinar objetos e classes em estruturas maiores.
Adapter (Adaptador)
Permite que objetos com interfaces incompatíveis trabalhem juntos. Um exemplo clássico é a integração de bibliotecas de terceiros ou o trabalho com código legado.
// Protocolo antigoprotocol OldPaymentSystem { func pay(amount: Double)}
// Novo protocoloprotocol NewPaymentSystem { func processPayment(amount: Double, currency: String)}
// Adaptadorclass PaymentAdapter: NewPaymentSystem { private let oldSystem: OldPaymentSystem init(oldSystem: OldPaymentSystem) { self.oldSystem = oldSystem } func processPayment(amount: Double, currency: String) { // Conversão de moeda let convertedAmount = amount * 1.1 oldSy