Principios SOLID en Kotlin: de la teoría a la práctica
SOLID es el acrónimo de cinco principios fundamentales del diseño orientado a objetos, formulados por Robert Martin (Tío Bob). Estos principios ayudan a crear código flexible, escalable y fácil de mantener. En este artículo, analizaremos cada principio SOLID con ejemplos del mundo de Kotlin, para que puedas aplicarlos inmediatamente en tus proyectos.
1. Single Responsibility Principle (SRP) — Principio de responsabilidad única
Teoría: Cada clase debe tener una sola razón para cambiar. En otras palabras, la clase debe ser responsable de una funcionalidad claramente definida.
Práctica en Kotlin: Consideremos una violación típica de SRP, donde la clase se encarga tanto del procesamiento de datos, como de la salida y la validación.
// ❌ Violación de SRPclass UserManager { fun registerUser(email: String, password: String) { if (isValidEmail(email) && isValidPassword(password)) { saveToDatabase(email, password) sendWelcomeEmail(email) } }
private fun isValidEmail(email: String): Boolean = email.contains("@") private fun isValidPassword(password: String): Boolean = password.length >= 6 private fun saveToDatabase(email: String, password: String) { /* ... */ } private fun sendWelcomeEmail(email: String) { /* ... */ }}Refactorización cumpliendo con SRP:
// ✅ Cumplimiento de SRPclass UserValidator { fun isValidEmail(email: String): Boolean = email.contains("@") fun isValidPassword(password: String): Boolean = password.length >= 6}
class UserRepository { fun save(email: String, password: String) { /* Guardar en BD */ }}
class EmailService { fun sendWelcomeEmail(email: String) { /* Enviar email */ }}
class UserRegistrationService( private val validator: UserValidator, private val repository: UserRepository, private val emailService: EmailService) { fun registerUser(email: String, password: String) { if (validator.isValidEmail(email) && validator.isValidPassword(password)) { repository.save(email, password) emailService.sendWelcomeEmail(email) } }}2. Open/Closed Principle (OCP) — Principio de abierto/cerrado
Teoría: Las entidades de software (clases, módulos, funciones) deben estar abiertas para la extensión, pero cerradas para la modificación. Debes poder agregar nueva funcionalidad sin modificar el código existente.
Práctica en Kotlin: Usamos interfaces y polimorfismo. En lugar de if-else o when para manejar diferentes tipos, crearemos una jerarquía.
// ❌ Violación de OCPclass DiscountCalculator { fun calculateDiscount(customerType: String, amount: Double): Double { return when (customerType) { "Regular" -> amount * 0.05 "Premium" -> amount * 0.10 "VIP" -> amount * 0.20 else -> 0.0 } } // ¡Para agregar "Gold", hay que modificar este método!}// ✅ Cumplimiento de OCPinterface DiscountStrategy { fun applyDiscount(amount: Double): Double}
class RegularDiscount : DiscountStrategy { override fun applyDiscount(amount: Double): Double = amount * 0.05}
class PremiumDiscount : DiscountStrategy { override fun applyDiscount(amount: Double): Double = amount * 0.10}
class VIPDiscount : DiscountStrategy { override fun applyDiscount(amount: Double): Double = amount * 0.20}
// Nuevo tipo se agrega sin modificar el código existenteclass GoldDiscount : DiscountStrategy { override fun applyDiscount(amount: Double): Double = amount * 0.15}
class DiscountCalculator { fun calculateDiscount(strategy: DiscountStrategy, amount: Double): Double { return strategy.apply