The Single Responsibility Principle (SRP)
is a cornerstone of object-oriented design, closely associated with the SOLID principles
. It emphasizes that a class should have only one reason to change, meaning it should have a single responsibility or purpose.
What is SRP?
The principle asserts that a class should do only one thing and do it very well. This doesn’t imply that a class should have only one method or behavior, but rather that it should contain a cohesive set of behaviors related to a single responsibility.
Other SOLID principles
- Single Responsibility Principle
- Open Closed Principle
- Liskov Substitution Problem
- Interface Segregation Principle
- Dependency Inversion Principle
Let’s explore SRP with an example.
Code without SRP
It is the code representation in c#:
public class Book
{
public string Title { get; }
public string Author { get; }
public Book(string title, string author)
{
Title = title;
Author = author;
}
public void Print()
{
Console.WriteLine($"Printing Book: {Title} by {Author}");
}
public void SaveBook(string filePath)
{
Console.WriteLine("Saving book to file: " + filePath);
}
}
Analyzing the Code
Does the Book
class adhere to the SRP
? Let’s break down its responsibilities:
- Representing Book Data: Properties like
Title
andAuthor
. - Managing Book Data: The
SaveBook
method. - Printing Book Details: The
Print
method.
Clearly, the Book
class handles multiple responsibilities.
Problems with Multiple Responsibilities
📢 Change is the only constant in the software.
You might wonder, what’s the harm in having multiple responsibilities in a single class? Here are some potential issues:
1. Changing printing format:
Suppose a client requests a change in the print format. Modifying the Print
method might inadvertently introduce bugs. Since the Book
class is used in various parts of the software, these bugs could propagate, making the code difficult to maintain.
2. Altering the SaveFile logic:
If the saving logic changes (e.g., saving to a database instead of a file), updating the SaveBook
method could similarly introduce bugs, affecting all parts of the software that use the Book
class.
3. Adding new functionality:
Adding new features, like exporting the book to a PDF
, increases the complexity of the Book
class if it already handles multiple responsibilities.
4. Testing complexity:
A class with multiple responsibilities can lead to complex unit tests, as tests must account for various concerns.
Problems Of Not Following SRP
- Harder to Maintain: Changes to one responsibility might break others, making the code harder to maintain.
- Understanding challenges: New developers might struggle to understand a class with multiple responsibilities.
- Reduced reusability: If you need only the print functionality, you still have to include the save functionality, reducing reusability.
- Poor Testability: Testing becomes more difficult as tests need to cover multiple responsibilities.
Refactored Example Following SRP
--- title: Follows SRP --- classDiagram class Book{ +string Title, +string Author } class BookPrinter{ +Print(Book) } class BookRepository{ +SaveBook(Book, string) }
We can separate the responsibilities into different classes.
BookClass
for managing book details.BookPrinter
for printing the book.BookRepository
for saving the book
Here is the refactored code.
// Book.cs
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
}
// BookPrinter.cs
public class BookPrinter
{
public void Print(Book book)
{
Console.WriteLine($"Printing Book: {book.Title} by {book.Author}");
}
}
// BookRepository.cs
public class BookRepository
{
public void SaveBook(Book book, string filePath)
{
Console.WriteLine("Saving book to file: " + filePath);
}
}
By separating these responsibilities, each class now has single reason to change:
- The
Book
class will change if the structure of book detail changes. - The
BookPrinter
class will change if the printing logic changes. - The
BookRepository
class will change if the saving logic changes.
This makes the code more maintainable, testable, and adheres to the Single Responsibility Principle.