Introducción: SOLID y Rust — una combinación ideal
\nLos principios SOLID son reglas fundamentales del diseño orientado a objetos que ayudan a crear código flexible, mantenible y escalable. Aunque Rust no es un lenguaje puramente orientado a objetos (utiliza traits y estructuras en lugar de clases), los principios SOLID son totalmente aplicables a él. En este artículo, analizaremos cada uno de los cinco principios con ejemplos de código en Rust, mostrando cómo ayudan a construir sistemas robustos.
\nA lo largo del artículo, verá cómo Rust, con su sistema de propiedad, traits y genéricos, hace que la implementación de SOLID sea natural y potente. Comenzaremos con Single Responsibility y terminaremos con Dependency Inversion, proporcionando ejemplos listos para usar.
\n\n1. Single Responsibility Principle (SRP) — principio de responsabilidad única
\nEsencia: Cada módulo, clase o función debe tener solo una razón para cambiar. En Rust, esto significa que una estructura debe encargarse de una sola tarea.
\n\nEjemplo incorrecto (violación de SRP)
\nstruct Report {\n title: String,\n content: String,\n}\n\nimpl Report {\n fn generate(&self) -> String {\n format!("# {}\\n\\n{}", self.title, self.content)\n }\n\n fn save_to_file(&self, path: &str) -> std::io::Result<()> {\n std::fs::write(path, self.generate())?;\n Ok(())\n }\n\n fn send_email(&self, recipient: &str) {\n println!("Sending email to {} with report", recipient);\n }\n}\nAquí, la estructura Report se encarga de la generación, el guardado y el envío — tres razones diferentes para cambiar. Esto viola SRP.
Ejemplo correcto (cumplimiento de SRP)
\nstruct Report {\n title: String,\n content: String,\n}\n\nimpl Report {\n fn generate(&self) -> String {\n format!("# {}\\n\\n{}", self.title, self.content)\n }\n}\n\nstruct ReportSaver;\n\nimpl ReportSaver {\n fn save(&self, report: &Report, path: &str) -> std::io::Result<()> {\n std::fs::write(path, report.generate())?;\n Ok(())\n }\n}\n\nstruct EmailSender;\n\nimpl EmailSender {\n fn send(&self, recipient: &str, message: &str) {\n println!("Sending email to {}: {}", recipient, message);\n }\n}\nAhora cada estructura se encarga de su propia tarea: Report — de los datos y la generación, ReportSaver — del guardado, EmailSender — del envío. Esto simplifica las pruebas y el mantenimiento.
2. Open-Closed Principle (OCP) — principio de abierto/cerrado
\nEsencia: Las entidades de software deben estar abiertas para la extensión, pero cerradas para la modificación. En Rust, esto se logra mediante traits y genéricos.
\n\nEjemplo: sistema de filtrado
\ntrait Filter<T> {\n fn apply(&self, items: &[T]) -> Vec<T>;\n}\n\nstruct EvenFilter;\n\nimpl Filter<i32> for EvenFilter {\n fn apply(&self, items: &[i32]) -> Vec<i32> {\n items.iter().filter(|&x| x % 2 == 0).copied().collect()\n }\n}\n\nstruct GreaterThanFilter {\n threshold: i32,\n}\n\nimpl Filter<i32> for GreaterThanFilter {\n fn apply(&self, items: &[i32]) -> Vec<i32> {\n items.iter().filter(|&&x| x > self.threshold).copied().collect()\n }\n}\n\nfn process<T: Clone, F: Filter<T>>(items: &[T], filter: F) -> Vec<T> {\n filter.apply(items)\n}\n\nfn main() {\n let numbers = vec![1, 2, 3, 4, 5, 6];\n let even = process(&numbers, EvenFilter);\n let greater = process(&numbers, GreaterThanFilter { threshold: 3 });\n println!("Even: {:?}, Greater: {:?}", even, greater);\n}\nPodemos agregar nuevos filtros sin modificar el código existente de process. Esta es una implementación de OCP mediante polimorfismo de traits.
3. Liskov Substitution Principle (LSP) — principio de sustitución de Barbara Liskov
\nEsencia:
Blogs
Book Recommendations
Leer también
Rust en 2025: principales novedades del lenguaje y el ecosistema
¿Atrapaste un NetworkOnMainThreadException en 2025? Guía completa para solucionarlo en Java
Ansible: automatización DevOps para principiantes
¿Por qué la diferencia de fechas en 1927 rompe el código? Top errores de Java
Cómo conseguir trabajo como desarrollador TypeScript: consejos y currículum en la práctica