What is Single Responsibility Principle?
- Single Responsibility Principle is one of the five principles of SOLID acronym.
- Single Responsibility Principle (SRP) says that “a class should have only one reason to change”
- Everyone likes a “Jack of all trades, master of none”
- “Is it really a good in software design”? Will it be good for a single class, to provide all the required functionalities?
In ‘Principles of Object Oriented Design (OOD)’ Robert C Martin, define ‘responsibility‘ to be ‘a reason to change’.
- If a class has more than one ‘responsibility’, that means the class has more than ‘one reason to change’.
- If a class has more than one functionality it should be fixed by moving the additional responsibilities to new classes.
- When we start adopting Single Responsibility principle, It will prevents the unwanted changes to our class.
Example: Employee class to analyze Single Responsible Principle
package org.learn.srp; //enum representing department of employee enum Department_t { HR, FINANCE, DISPLAY, CONSUMER_ELECTRONICS } // Dummy class ..It will contain data members/methods to interact with database class DatabaseHandler { } public class Employee { String name; int empId; int salary; Department_t department; public Employee(String name, int emp_id, Department_t department) { // Update the data member; } int updateSalary(int new_slary) { // Update salary of employee // ............... // ........ return 0; } void change_department(Department_t department) { // Change department of employee // ...code goes here // ...... } int update_employee_database(DatabaseHandler db) { // Update salary of employee in database // ............... // ........ return 0; } };
//enum representing department of employee typedef enum Department { HR, FINANCE, DISPLAY, CONSUMER_ELECTRONICS } Department_t; // Dummy class ..It will contain data members/methods of database class DatabaseHandler; class Employee { public: Employee(std::string name, int emp_id, Department_t department) { // Update the data member; } int update_salary(int new_slary) { // Update salary of employee // ............... // ........ return 0; } void change_department(Department_t department) { // Change department of employee // ...code goes here // ...... } int update_employee_database(DatabaseHandler& db) { // Update salary of employee in database // ............... // ........ return 0; } private: std::string m_name; int m_emp_id; int m_salary; };
Analyze Employee class (Single Responsibility Principle):
- It is prudent for the Employee class to provide a member function to update the salary and department of the Employee object.
- They share the same responsibility of maintaining correct state of the Employee object.
- But what about the ‘update_employee_database(DatabaseHandler& db) ?
- The method update_employee_database updates the database, which holds the Employee records.
The million-dollar question: Should update_employee_database method be part of the Employee class? Going by SLP, answer should be NO. Responsibility of updating the database should not be part of the Employee class. A change in update logic of employee table in database, could introduce a change in the Employee class, which is completely undesirable. Updating the database records should be handled by a separate class.
Developers unknowingly add more responsibility to a class, when there is bug fix or when they try to add a new functionality to a software.
- One problem often noted, with practicing SRP is increasingly, large number of smaller classes. Because it is at the discretion of developer, how developer defines a responsibility. Moreover, having large number of classes is always better than having one huge class, which is catering multiple functionalities.
- Another counter argument for SRP is having bigger class with more than one responsibility will result in more cohesive class. That is a decision, that the designer/developer has to take, anticipating how frequently the functionality can change.
- Also there are debates on why having a single responsibility in a class is better than having two or three cohesive responsibilities. That is something which should be left to the judgment of the designer/devloper.
The idea or aim behind SRP is to prevent unwanted and unrelated changes to a class. If we are achieving it then we are on right track to meet the objective of SRP.