Introducción: Por qué SOLID es la base del código C# de calidad
Desarrollar en C# dentro del ecosistema .NET requiere no solo conocimiento de sintaxis, sino también la capacidad de diseñar aplicaciones flexibles, mantenibles y comprobables. SOLID es el acrónimo de cinco principios fundamentales de diseño orientado a objetos, formulados por Robert Martin. Ayudan a los desarrolladores a evitar dependencias "rígidas", duplicación de código y problemas al escalar.
En este artículo analizaremos cada uno de los cinco principios SOLID aplicados a C#: desde la teoría hasta ejemplos de código reales. Aprenderá cómo la refactorización teniendo en cuenta SOLID hace que su código sea más limpio y el mantenimiento de proyectos sea más sencillo.
1. Single Responsibility Principle (SRP) — Principio de responsabilidad única
Teoría
Una clase debe tener solo una razón para cambiar. En otras palabras, cada clase es responsable de exactamente una funcionalidad o lógica de negocio. Si una clase hace demasiado, se vuelve difícil de probar, modificar y reutilizar.
Práctica: violación de SRP
public class OrderProcessor{ public void ProcessOrder(Order order) { // 1. Validación del pedido if (order.Total <= 0) throw new Exception("Invalid order"); // 2. Guardar en la base de datos using var db = new AppDbContext(); db.Orders.Add(order); db.SaveChanges(); // 3. Enviar notificación por email SmtpClient client = new SmtpClient(); client.Send("admin@shop.com", order.CustomerEmail, "Order confirmed", "Thank you!"); }}Aquí OrderProcessor viola SRP: es responsable de la validación, el trabajo con la base de datos y el envío de email. Cambiar la lógica de envío de notificaciones requeriría modificar esta misma clase.
Refactorización con SRP
public class OrderValidator{ public bool Validate(Order order) => order.Total > 0;}
public class OrderRepository{ public void Save(Order order) { using var db = new AppDbContext(); db.Orders.Add(order); db.SaveChanges(); }}
public class EmailService{ public void SendConfirmation(string email) { SmtpClient client = new SmtpClient(); client.Send("admin@shop.com", email, "Order confirmed", "Thank you!"); }}
public class OrderProcessor{ private readonly OrderValidator _validator; private readonly OrderRepository _repository; private readonly EmailService _emailService;
public OrderProcessor(OrderValidator validator, OrderRepository repository, EmailService emailService) { _validator = validator; _repository = repository; _emailService = emailService; }
public void ProcessOrder(Order order) { if (!_validator.Validate(order)) throw new Exception("Invalid order"); _repository.Save(order); _emailService.SendConfirmation(order.CustomerEmail); }}Ahora cada clase tiene un área de responsabilidad. Esto simplifica las pruebas y la modificación.
2. Open/Closed Principle (OCP) — Principio de abierto/cerrado
Teoría
Las entidades de software (clases, módulos, funciones) deben estar abiertas para extensión, pero cerradas para modificación. Es decir, debe poder agregar nueva funcionalidad sin modificar el código existente.
Práctica: violación de OCP
public class ShapeDrawer{ public void DrawShape(object shape) { if (shape is Circle circle) Console.WriteLine($"Drawing circle with radius {circle.Radius}"); else if (shape is Rectangle rect) Console.WriteLine($"Drawing rectangle {rect.Width}x{rect.Height}"); // ¡Al agregar un nuevo tipo de figura, este método debe modificarse! }}Refactorización con OCP mediante abstracción
public abstract c