Single Responsibility Principle


In this article we are going to discuss Single Responsibility Principle in C#. There are many blogs, articles are available on the internet regarding Single Responsibility Principle but in this particular article I will try to explain to you with as much as simple.

Single Responsibility Principle

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

SOLID Principals in C#

Violating the Single Responsibility Principle

Let's look at an example of code that violates the Single Responsibility Principle.

Example of a Class Violating SRP

public class OrderProcessor
{
    public void ProcessOrder(Order order)
    {
        // Validate order
        if (order.IsValid)
        {
            // Save order to database
            SaveOrderToDatabase(order);

            // Send confirmation email
            SendConfirmationEmail(order);
        }
    }

    private void SaveOrderToDatabase(Order order)
    {
        // Code to save order to the database
        Console.WriteLine("Order saved to database.");
    }

    private void SendConfirmationEmail(Order order)
    {
        // Code to send confirmation email
        Console.WriteLine("Confirmation email sent.");
    }
}

In this example, the OrderProcessor class has multiple responsibilities:

  • validating the order(validation logic).
  • Saving the order to the database.
  • Sending a confirmation email.

Problems with Violating SRP

  1. Harder to Maintain - Changes in the email sending process or database saving process will require changes to the OrderProcessor class.
  2. Difficult to Test - Testing the OrderProcessor class will be more complex because it involves testing multiple responsibilities at once.
  3. Reduced Reusability - The code for sending emails and saving to the database cannot be reused easily in other parts of the application.

Refactoring to Adhere to SRP

To adhere to the Single Responsibility Principle, we should refactor the code so that each class has only one responsibility. The below code define the refactor of above violating code.

Example

public interface IOrderRepository
{
    void SaveOrder(Order order);
}

public class OrderRepository : IOrderRepository
{
    public void SaveOrder(Order order)
    {
        // Code to save order to the database
        Console.WriteLine("Order saved to database.");
    }
}

public interface IEmailService
{
    void SendEmail(Order order);
}

public class EmailService : IEmailService
{
    public void SendEmail(Order order)
    {
        // Code to send confirmation email
        Console.WriteLine("Confirmation email sent.");
    }
}

public class OrderProcessor
{
    private readonly IOrderRepository _orderRepository;
    private readonly IEmailService _emailService;

    public OrderProcessor(IOrderRepository orderRepository, IEmailService emailService)
    {
        _orderRepository = orderRepository;
        _emailService = emailService;
    }

    public void ProcessOrder(Order order)
    {
        // Validate order
        if (order.IsValid)
        {
            // Save order to database
            _orderRepository.SaveOrder(order);

            // Send confirmation email
            _emailService.SendEmail(order);
        }
    }
}

Single Responsibility Principle Benefits

The SRP has many benefits to improve code complexity and maintenance. Some benefits of SRP are following,

  1. Reduction in complexity of a code - A code is based on its functionality. A method holds logic for a single functionality or task. So, it reduces the code complexity.
  2. Increased readability, extensibility, and maintenance - As each method has a single functionality so it is easy to read and maintain.
  3. Reusability and Reduced Error -  As code separates based functionality so if the same functionality uses somewhere else in an application then don’t write it again.
  4. Better Testability- In the maintenance, when a functionality changes then we don’t need to test the entire model.
  5. Reduced Coupling - It reduced the dependency code. A method’s code doesn’t depend on other methods.

Prev Next