Single Responsibility Principle

The Single Responsibility Principle (SRP) is one of the five SOLID principles of object-oriented design. It states that a class should have one, and only one, reason to change. This means that a class should have only one responsibility or job.

When a class has more than one responsibility, it becomes coupled and can lead to issues when one responsibility changes. In layman's terminology, this means that a class should not be loaded with multiple responsibilities, and a single responsibility should not be spread across multiple classes or mixed with other responsibilities. The reason is that the more changes requested in the future, the more changes the class needs to apply.

Understanding the Single Responsibility Principle in C#

  • A module or class should have a very small piece of responsibility in the entire application. As it states, a class/module should have no more than one reason to change.

  • Classes, software components, and modules that have only one responsibility are much easier to explain, implement, and understand than ones that give a solution for everything.

  • This also reduces the number of bugs/issues, improves development speed, and makes the developer’s life a lot easier.

  • It’s easy to verify that it's working according to the logic defined, and it’s easy to change in class as it has a single responsibility.

The Single Responsibility Principle gives us a good way of identifying classes at the design phase of an application, and it makes you think of all the ways a class can change. However, a good separation of responsibilities is done only when we have the full picture of how the application should work. Let us check this with an example.

Example of Single Responsibility Principle in C#

Bad Example (Violation of SRP)

Here’s a class that violates the Single Responsibility Principle



public class User
{
    public string Name { get; set; }
    public string Email { get; set; }

    public void SaveToDatabase()
    {
        // Logic to save user to database
    }

    public void SendEmail(string message)
    {
        // Logic to send email
    }
}

Good Example (Adhering to SRP)

We can refactor this class to adhere to the Single Responsibility Principle by separating the concerns:



public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class UserRepository
{
    public void Save(User user)
    {
        // Logic to save user to database
    }
}

public class EmailService
{
    public void SendEmail(string email, string message)
    {
        // Logic to send email
    }
}

Explanation
  1. User Class: Now, the User class is responsible only for holding user data.

  2. UserRepository Class: The UserRepository is responsible for the data access layer, specifically saving the user to the database.

  3. EmailService Class: The EmailService class is responsible for sending emails.
Benefits of using SRP
  1. Easier Maintenance: Changes in one part of the application won't affect the User class.

  2. Improved Readability: Each class has a clear purpose, making it easier for developers to understand the code.

  3. Enhanced Testability: Classes can be tested independently. For example, you can test UserRepository without involving the email logic.
Conclusion

By following the Single Responsibility Principle, you create a more modular and maintainable codebase, making it easier to manage changes over time. This principle helps to reduce the complexity of classes and encourages better software design.