Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
35m 50s
Los patrones de diseño son soluciones reutilizables a problemas comunes de desarrollo de software, que proporcionan plantillas para estructurar e implementar código orientado a objetos de una manera más eficiente y fácil de mantener. Ayudan a los desarrolladores a resolver problemas de creación, estructura y comunicación de objetos de forma flexible y escalable. Los patrones de diseño sirven como conceptos de mejores prácticas que guían a los desarrolladores a la hora de escribir mejor código. Uno de los principios fundamentales en el diseño de software es el Principio de Responsabilidad Única (SRP), que forma parte de los principios SOLID.
En su vídeo, "Patrones de diseño: Single Responsibility Principle Explained Practically in C# (The S in SOLID)", Tim Corey explora el Principio de Responsabilidad Única (SRP), destacando su importancia en el diseño de software y proporcionando ideas prácticas sobre cómo implementarlo de manera efectiva. Este artículo ofrece una visión general concisa de los puntos clave de su vídeo, haciendo hincapié en la importancia de la SRP en la creación de código limpio y mantenible.
En el diseño de software, los principios SOLID son cruciales para crear código mantenible y escalable. Garantizan que el código sea fácil de entender, probar y modificar. Los cinco principios -Principio de Responsabilidad Única (SRP), Principio Abierto/Cerrado (OCP), Principio de Sustitución de Liskov (LSP), Principio de Segregación de Interfaces (ISP) y Principio de Inversión de Dependencias (DIP)- forman parte integral del diseño orientado a objetos y pueden aplicarse dentro de los patrones de diseño para hacer que las soluciones sean más robustas.
Mediante la aplicación de patrones de diseño en C#, los desarrolladores pueden resolver problemas comunes con mayor eficacia. Ya se trate de crear objetos, definir estructuras de árbol o garantizar la reutilización con instancias únicas, los patrones de diseño proporcionan soluciones predefinidas que mejoran la arquitectura del software. Patrones como Factory Method, Builder y Singleton proporcionan soluciones flexibles y reutilizables, mientras que los patrones estructurales y de comportamiento ayudan a gestionar la complejidad y mejorar la comunicación dentro de los sistemas. Al aprender y utilizar estos patrones, los desarrolladores pueden crear sistemas más fáciles de mantener y ampliar.
Tim analiza el concepto de SRP, haciendo hincapié en que es crucial que los desarrolladores se aseguren de que su código se adhiere a las mejores prácticas. SRP establece que una clase debe tener una sola responsabilidad o razón para cambiar. Este principio ayuda a mantener un código limpio, mantenible y escalable.
Tim crea una sencilla aplicación de consola en C# que solicita el nombre y los apellidos del usuario, los valida y genera un nombre de usuario. La implementación inicial viola SRP, proporcionando una excelente oportunidad para demostrar cómo refactorizar el código para adherirse a este principio.
Tim explica SRP destacando las múltiples responsabilidades dentro de la clase inicial:
Cada una de estas responsabilidades representa una razón diferente para que la clase cambie, violando la SRP.
Tim demuestra cómo refactorizar el código para seguir SRP extrayendo cada responsabilidad en su propia clase. Este enfoque garantiza que cada clase tenga un único motivo de cambio, lo que hace que el código sea más modular y fácil de mantener.
Tim ofrece un ejemplo práctico de refactorización:
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to my application");
Console.Write("Enter your first name: ");
string firstName = Console.ReadLine();
Console.Write("Enter your last name: ");
string lastName = Console.ReadLine();
if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
{
Console.WriteLine("You did not give us valid information!");
Console.ReadLine();
return;
}
var userName = $"{firstName.Substring(0, 1)}{lastName}".ToLower();
Console.WriteLine($"Your username is {userName}");
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}Imports System
Module Program
Sub Main(args As String())
Console.WriteLine("Welcome to my application")
Console.Write("Enter your first name: ")
Dim firstName As String = Console.ReadLine()
Console.Write("Enter your last name: ")
Dim lastName As String = Console.ReadLine()
If String.IsNullOrWhiteSpace(firstName) OrElse String.IsNullOrWhiteSpace(lastName) Then
Console.WriteLine("You did not give us valid information!")
Console.ReadLine()
Return
End If
Dim userName = $"{firstName.Substring(0, 1)}{lastName}".ToLower()
Console.WriteLine($"Your username is {userName}")
Console.WriteLine("Press enter to close...")
Console.ReadLine()
End Sub
End ModuleEn primer lugar, Tim crea una clase para gestionar los mensajes estándar que se muestran al usuario. Esta clase gestionará los mensajes de bienvenida y los mensajes finales.
public class StandardMessages
{
public static void WelcomeMessage()
{
Console.WriteLine("Welcome to my application");
}
public static void EndApplication()
{
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
public static void ShowValidationErrorMessage()
{
Console.WriteLine("You did not give us valid information!");
}
}Public Class StandardMessages
Public Shared Sub WelcomeMessage()
Console.WriteLine("Welcome to my application")
End Sub
Public Shared Sub EndApplication()
Console.WriteLine("Press enter to close...")
Console.ReadLine()
End Sub
Public Shared Sub ShowValidationErrorMessage()
Console.WriteLine("You did not give us valid information!")
End Sub
End ClassEn la clase Program, sustituye las llamadas directas a Console.WriteLine y Console.ReadLine por llamadas a los métodos de la clase StandardMessages:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
// Other code...
StandardMessages.EndApplication();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
' Other code...
StandardMessages.EndApplication()
End Sub
End ModuleA continuación, Tim crea una clase para capturar el nombre y los apellidos de la persona. Esta clase será responsable de recoger la entrada del usuario y devolver un objeto Persona.
public class PersonDataCapture
{
public static Person Capture()
{
Person output = new Person();
Console.Write("Enter your first name: ");
output.FirstName = Console.ReadLine();
Console.Write("Enter your last name: ");
output.LastName = Console.ReadLine();
return output;
}
}Public Class PersonDataCapture
Public Shared Function Capture() As Person
Dim output As New Person()
Console.Write("Enter your first name: ")
output.FirstName = Console.ReadLine()
Console.Write("Enter your last name: ")
output.LastName = Console.ReadLine()
Return output
End Function
End ClassTambién se necesita una clase Person para contener el nombre y los apellidos del usuario.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}Public Class Person
Public Property FirstName As String
Public Property LastName As String
End ClassEn la clase Program, sustituya el manejo directo de la entrada del usuario por una llamada a PersonDataCapture.Capture:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
// Other code...
StandardMessages.EndApplication();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
' Other code...
StandardMessages.EndApplication()
End Sub
End ModuleA continuación, Tim crea una clase para gestionar la validación del nombre y apellidos de la persona. Esta clase se encargará de garantizar que los nombres no contengan nulos ni espacios en blanco.
public class PersonValidator
{
public static bool Validate(Person person)
{
if (string.IsNullOrWhiteSpace(person.FirstName))
{
StandardMessages.ShowValidationErrorMessage("first name");
return false;
}
if (string.IsNullOrWhiteSpace(person.LastName))
{
StandardMessages.ShowValidationErrorMessage("last name");
return false;
}
return true;
}
}Public Class PersonValidator
Public Shared Function Validate(person As Person) As Boolean
If String.IsNullOrWhiteSpace(person.FirstName) Then
StandardMessages.ShowValidationErrorMessage("first name")
Return False
End If
If String.IsNullOrWhiteSpace(person.LastName) Then
StandardMessages.ShowValidationErrorMessage("last name")
Return False
End If
Return True
End Function
End ClassEn la clase Program, sustituye el código de validación por una llamada a PersonValidator.Validate:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
if (!PersonValidator.Validate(user))
{
StandardMessages.EndApplication();
return;
}
// Other code...
StandardMessages.EndApplication();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
If Not PersonValidator.Validate(user) Then
StandardMessages.EndApplication()
Return
End If
' Other code...
StandardMessages.EndApplication()
End Sub
End ModuleTim traslada la lógica de generación de nombres de usuario y creación de cuentas a una nueva clase AccountGenerator.
Creación de la clase AccountGenerator:
public class AccountGenerator
{
public static void CreateAccount(Person user)
{
string username = $"{user.FirstName.Substring(0, 1)}{user.LastName}".ToLower();
Console.WriteLine($"Your username is: {username}");
}
}Public Class AccountGenerator
Public Shared Sub CreateAccount(user As Person)
Dim username As String = $"{user.FirstName.Substring(0, 1)}{user.LastName}".ToLower()
Console.WriteLine($"Your username is: {username}")
End Sub
End ClassActualización de la clase principal:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
bool isUserValid = PersonValidator.Validate(user);
if (!isUserValid)
{
StandardMessages.EndApplication();
return;
}
AccountGenerator.CreateAccount(user);
StandardMessages.EndApplication();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
Dim isUserValid As Boolean = PersonValidator.Validate(user)
If Not isUserValid Then
StandardMessages.EndApplication()
Return
End If
AccountGenerator.CreateAccount(user)
StandardMessages.EndApplication()
End Sub
End Module
En esta sección final, Tim Corey resume las ventajas y la aplicación del principio de responsabilidad única (SRP) a través del proceso de refactorización del código de demostración. Destaca las ventajas de dividir la aplicación en clases más pequeñas y centradas.
Mantenimiento simplificado del código:
Cada clase tiene una única responsabilidad, lo que facilita la localización de los cambios que deben realizarse. Por ejemplo, la lógica de captura de datos de usuario se sitúa claramente en PersonDataCapture.
Esta estructura simplifica la comprensión, ya que cualquiera que desee modificar la validación de usuarios sabe que debe consultar PersonValidator.
Mejora de la legibilidad:
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
bool isUserValid = PersonValidator.Validate(user);
if (!isUserValid)
{
StandardMessages.EndApplication();
return;
}
AccountGenerator.CreateAccount(user);
StandardMessages.EndApplication();StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
Dim isUserValid As Boolean = PersonValidator.Validate(user)
If Not isUserValid Then
StandardMessages.EndApplication()
Return
End If
AccountGenerator.CreateAccount(user)
StandardMessages.EndApplication()Complejidad reducida:
Las clases pequeñas con responsabilidades específicas suelen tener menos líneas de código, lo que facilita su comprensión y mantenimiento.
Ejemplo: Los métodos de la clase StandardMessages son concisos y sirven para un único propósito, como mostrar un mensaje de bienvenida o finalizar la aplicación.
public class StandardMessages
{
public static void WelcomeMessage()
{
Console.WriteLine("Welcome to my application");
}
public static void EndApplication()
{
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
public static void ShowValidationErrorMessage(string fieldName)
{
Console.WriteLine($"You did not give us a valid {fieldName}!");
}
}Public Class StandardMessages
Public Shared Sub WelcomeMessage()
Console.WriteLine("Welcome to my application")
End Sub
Public Shared Sub EndApplication()
Console.WriteLine("Press enter to close...")
Console.ReadLine()
End Sub
Public Shared Sub ShowValidationErrorMessage(fieldName As String)
Console.WriteLine($"You did not give us a valid {fieldName}!")
End Sub
End Class
Facilidad de cambios de código:
Dado que cada clase tiene un único motivo de cambio, modificar el código en respuesta a nuevos requisitos resulta sencillo.
Ejemplo: Si el requisito es cambiar el mensaje final, el cambio se produce únicamente en el método StandardMessages.EndApplication.
Mejor depuración y colaboración:
Con clases más pequeñas y bien definidas, la depuración resulta más sencilla, ya que se puede localizar fácilmente un problema.
Los nuevos desarrolladores pueden incorporarse más rápidamente, entendiendo la estructura clara y las responsabilidades de cada clase.
Tim aborda la preocupación común de que la aplicación de SRP da lugar a demasiadas clases, lo que hace que el proyecto sea engorroso:
Navegación y comprensión:
Herramientas como IntelliSense en Visual Studio facilitan la navegación por varias clases. Por ejemplo, pulsando F12 se accede directamente a la definición de métodos o clases.
Tener muchas piezas pequeñas y manejables puede facilitar la comprensión de toda la aplicación en comparación con las grandes clases monolíticas.
Rendimiento y almacenamiento:
Saldo y exceso :
Tim aconseja encontrar un equilibrio. Si la responsabilidad de una clase hace que crezca demasiado, considere si tiene múltiples razones para cambiar, lo que indica que puede necesitar una división adicional.
Sugiere que si es necesario desplazarse mucho por una clase en Visual Studio, puede que sea demasiado grande y sea necesario dividirla.
Tim anima a los desarrolladores a aplicar SRP gradualmente, especialmente en las bases de código existentes. Comience con pequeños cambios y código nuevo para alinearse con los principios de la SRP. Este enfoque gradual garantiza transiciones más fluidas y una mejora continua.
El ejemplo de refactorización de Tim Corey demuestra cómo la adhesión al Principio de Responsabilidad Única (SRP) da como resultado un código más limpio y fácil de mantener. Al dividir las responsabilidades en clases más pequeñas y específicas, los desarrolladores pueden mejorar la legibilidad, la depuración y la colaboración en sus bases de código. Este principio fundamental de los patrones de diseño SOLID allana el camino para principios más avanzados y mejores prácticas en el desarrollo de software.
Para obtener información más detallada y ejemplos de código, vea su vídeo y visite su canal para ver más vídeos sobre patrones de diseño.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy