Princípios SOLID em Kotlin: teoria e prática do A ao Z

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

Introdução: por que SOLID é importante em Kotlin?



SOLID é a sigla de cinco princípios fundamentais da programação orientada a objetos, formulados por Robert Martin (Tio Bob). No ecossistema Kotlin, que combina as melhores características da programação orientada a objetos e funcional, a observância dos princípios SOLID ajuda a criar código flexível, testável e de fácil manutenção. Esses princípios são especialmente relevantes para desenvolvimento Android, aplicações server-side com Ktor e sistemas multithread baseados em corrotinas.



Neste artigo, abordaremos cada um dos cinco princípios SOLID com exemplos adaptados aos idiomas do Kotlin. Você aprenderá como evitar erros comuns e tornar seu código não apenas funcional, mas verdadeiramente de qualidade.



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



Essência do princípio

Uma classe deve ter apenas um motivo para mudar. Em outras palavras, cada classe é responsável por exatamente uma funcionalidade.



Exemplo ruim (violação do SRP)

class UserManager {    fun createUser(name: String, email: String) { /* ... */ }    fun deleteUser(id: Int) { /* ... */ }    fun sendEmail(to: String, subject: String) { /* ... */ }    fun generateReport(userId: Int): String { /* ... */ }}

Aqui, UserManager é responsável pelo gerenciamento de usuários, envio de e-mails e geração de relatórios. Uma alteração na lógica de e-mail implicaria modificar esta classe, embora ela não devesse lidar com correspondência.



Exemplo bom (cumprimento do SRP)

class UserRepository {    fun createUser(name: String, email: String) { /* ... */ }    fun deleteUser(id: Int) { /* ... */ }}

class EmailService { fun sendEmail(to: String, subject: String) { /* ... */ }}

class ReportGenerator { fun generateReport(userId: Int): String { /* ... */ }}

Agora cada classe tem um único motivo para mudar. Isso simplifica os testes e a manutenção do código.



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



Essência do princípio

Entidades de software (classes, módulos, funções) devem estar abertas para extensão, mas fechadas para modificação. Isso significa que novos comportamentos são adicionados por meio de herança ou composição, e não alterando o código existente.



Exemplo ruim (violação do OCP)

class PaymentProcessor {    fun process(paymentType: String) {        when (paymentType) {            "credit_card" -> // processar cartão de crédito            "paypal" -> // processar PayPal            else -> throw IllegalArgumentException()        }    }}

Ao adicionar um novo método de pagamento (por exemplo, Apple Pay), seria necessário modificar PaymentProcessor, violando o OCP.



Exemplo bom (cumprimento do OCP)

interface PaymentMethod {    fun process(amount: Double)}

class CreditCardPayment : PaymentMethod { override fun process(amount: Double) { /* ... */ }}

class PayPalPayment : PaymentMethod { override fun process(amount: Double) { /* ... */ }}

class PaymentProcessor(private val method: PaymentMethod) { fun processPayment(amount: Double) { method.process(amount) }}

Agora, para adicionar um novo método de pagamento, basta criar uma classe que implemente PaymentMethod, sem tocar no código existente.



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



Essência do princípio

Objetos em um programa devem ser substituíveis por instâncias de seus subtipos sem alterar a correção do programa. Simplificando, se você tem uma classe Bird e uma subclasse Penguin, o código que funciona com Bird não deve quebrar ao substituí-lo por Penguin.



Exemplo ruim (violação do LSP)

open class Rectangle {    open var width: Int = 0                

Blogs

Book Recommendations