Princípios SOLID em Swift: teoria e prática para iOS/macOS

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course
Aqui está a tradução do conteúdo HTML educacional do russo para o português (Português), mantendo todas as tags HTML e os termos técnicos em inglês: ```html

Introdução: Por que SOLID é importante para um desenvolvedor Swift



O desenvolvimento para iOS e macOS exige não apenas conhecimento de frameworks, mas também a capacidade de criar uma arquitetura sustentável, testável e escalável. É aqui que os princípios SOLID entram em cena — cinco regras fundamentais de design orientado a objetos, formuladas por Robert Martin (Tio Bob).



Neste artigo, vamos analisar cada um dos cinco princípios SOLID com exemplos de código em Swift, mostrar antipadrões típicos e sugerir soluções corretas. Após a leitura, você será capaz de escrever código que é fácil de manter, estender e testar.



1. Single Responsibility Principle (SRP) — Princípio da Responsabilidade Única



Formulação: Uma classe deve ter apenas uma razão para mudar. Em outras palavras, cada módulo é responsável por exatamente uma funcionalidade.



Problema: Classe-monstro



Considere um exemplo típico do desenvolvimento iOS — a classe UserManager, que faz demais:



class UserManager {    func fetchUser() -> User { /* requisição de rede */ }    func saveUserToDatabase(_ user: User) { /* trabalho com CoreData */ }    func formatUserDisplayName(_ user: User) -> String { /* formatação */ }    func sendWelcomeEmail(to user: User) { /* envio de email */ }}


Aqui, a classe é responsável por requisições de rede, banco de dados, formatação de UI e envio de emails. Qualquer alteração em um desses aspectos levará a uma mudança no UserManager.



Solução: Separação de responsabilidades



class UserNetworkService {    func fetchUser() -> User { /* apenas requisição de rede */ }}

class UserDatabaseService { func saveUser(_ user: User) { /* apenas trabalho com BD */ }}

class UserFormatter { func displayName(for user: User) -> String { /* apenas formatação */ }}

class EmailService { func sendWelcome(to user: User) { /* apenas envio de email */ }}


Agora, cada classe tem uma responsabilidade clara, o que simplifica os testes e a modificação.



2. Open/Closed Principle (OCP) — Princípio do Aberto/Fechado



Formulação: Entidades de software devem estar abertas para extensão, mas fechadas para modificação.



Problema: Lógica rígida



Suponha que temos uma classe para calcular descontos:



class DiscountCalculator {    func calculateDiscount(for order: Order, customerType: String) -> Double {        if customerType == "regular" {            return order.total * 0.05        } else if customerType == "premium" {            return order.total * 0.1        } else if customerType == "vip" {            return order.total * 0.2        }        return 0    }}


Ao adicionar um novo tipo de cliente (gold), será necessário modificar a classe existente, o que viola o OCP.



Solução: Protocolos e polimorfismo



protocol DiscountStrategy {    func discount(for order: Order) -> Double}

struct RegularDiscount: DiscountStrategy { func discount(for order: Order) -> Double { order.total * 0.05 }}

struct PremiumDiscount: DiscountStrategy { func discount(for order: Order) -> Double { order.total * 0.1 }}

struct VIPDiscount: DiscountStrategy { func discount(for order: Order) -> Double { order.total * 0.2 }}

class DiscountCalculator { func calculateDiscount(for order: Order, using strategy: DiscountStrategy) -> Double { return strategy.discount(for: order) }}


Agora, para adicionar um novo desconto, basta criar uma nova estrutura que implemente o protocolo DiscountStrategy, sem modificar o DiscountCalculator.



3. Liskov Substitution Principle (LSP) — Princípio da Substituição de Barbara Liskov



Formulação: ```

Blogs

Book Recommendations