Introduction
The Single Responsibility Principle is a SOLID principle defined by Robert C. Martin. In principle, it says that an implementation (class/function) should perform only one task or implementation and it (class/function) should be changed for only one reason.
So in simple words, it says that whatever the developer implements (class/function) in code during development should perform only one task and the developer should only have one reason to change the implementation (class/function).
Wrong interpretation of the Principle
Most developers interpret this to mean that a class should perform only one task. But it's not only classes, functions you implement in code during development should also perform only one task. So one should interpret it as meaning that an implementation should perform only one task.
Real Life Example of not following Single Responsibility Principle
What happens when one can do more than one task? The following is an image of an example of it.
One can perform multiple tasks, there is no question of that, but it's not going to provide quality / better output.
So to get good quality/better output of work, one should do one task at a time.
Example of not following Principles in Application Development
In programming, in other words, when developing code as in the following, the Order class does not follow the principle.
Public class OrderManager
{
Public List < string > ValidateOrder()
{
//Code for validation
}
Public bool SaveOrder(OrderInfo order)
{
//Code for saving order
}
Public void NotifyCustomer()
{
//Code for notification
}
}
The preceding order class has the following responsibilities:
- ValidateOrder: Validating an order placed by the customer and return an error message if any
- SaveOrder: Saving an order placed by the customer and returns true/false
- NotifyCustomer: Notifies the customer order has been placed
Method not following the principle.
public int SumOfAllCustomerOrder(int customerId)
{
int sum = 0;
var query = “Select * from order where customerid = ” + customerid;;
//query orders
foreach(Order in OrderCollection)
{
If(Order.Items.Count > 5)
Sum += Order.Price;
}
return sum;
}
The preceding method has the following responsibilities.
- The method first all the orders
- It went through all orders in the collection and does some of that
Single Responsibility Principle
To make a class or function follow the Single Responsibility Principle, divide the responsibility by creating new classes or functions as in the following.
public class OrderValidator
{
public List<string> Validate(Order order)
{
// Code for validation
}
}
public class Notifier
{
public void Notify(string emailId)
{
// Code for notification
}
}
public class OrderManager
{
private readonly OrderValidator orderValidator;
private readonly Notifier notifier;
public OrderManager(OrderValidator oValidator, Notifier nFier)
{
orderValidator = oValidator;
notifier = nFier;
}
public bool SaveOrder(OrderInfo orderInfo)
{
// Validate order
orderValidator.Validate(orderInfo);
// Code for saving order
// This might be a call to repository to save order
// Notify after successful saving
notifier.Notify(orderInfo.EmailId);
}
public List<OrderInfo> GetOrders(int customerId)
{
// Code for getting order by customerId
}
}
The preceding code shows the three classes that have only a single responsibility to perform.
The method, it will be like.
public List < OrderInfo > GetOrder(int customerId)
{
int sum = 0;
var query = “Select * from order where customerid = ” + customerid;;
//query orders
return ordercollection;
}
public int SumOfAllCustomerOrder(int customerId)
{
var OrderCollection = GetOrder(customerId);
foreach(Order in OrderCollection)
{
If(Order.Items.Count > 5)
Sum += Order.Price;
}
return sum;
}
Note. Following the Single Responsibility doesn't mean one can create a class with only one method.
Disadvantages of not following the Single Responsibility Principle
In programming if the developer creates a class/function that performs more than one task then that always causes problems in providing good quality. The following problems are related to a class performing more than one task.
- It's very difficult for the other developers (in other words developers unfamiliar with the class) to understand the class/function.
- It's difficult for the other developers to maintain the class/function or change the class/function.
- Writing test cases for the class/function also becomes difficult.
How to determine if the Single Responsibility Principle has not been followed.
- Try to write a one-line description of the class or method, if the description contains words like "And, Or, But, or If" then that is a problem.
An example of a description of a class as described above that does not follow the single responsibility principle is:
“An Order class that performs order saving, notification to the customer, and validates the order”.
- A class constructor takes more than three arguments or a method contains too many parameters.
- A class or method as an implementation that is too long.
- A class that has low cohesion. Read more about cohesion: Cohesion
Further Read