Skip to main content
Create your own
Lesson illustration

Mastering SRP for Cohesive Classes

Hello! Welcome to the first lesson in our module on SOLID principles. These five principles are the bedrock of creating clean, maintainable, and flexible object-oriented designs—essential skills for any system design interview.

In our previous lesson, we explored immutable objects and how they contribute to creating safe and predictable code. An immutable object, by its very nature, has a very focused and singular purpose: to hold a consistent snapshot of data. This provides a natural bridge to our topic today, the very first of the SOLID principles: the Single Responsibility Principle (SRP).

The learning outcome for this lesson is to: Apply the Single Responsibility Principle (SRP) to create cohesive classes.

We'll dissect what this principle truly means, move beyond simplistic definitions, and see how you can use it to prevent your classes from becoming bloated, hard-to-maintain "god objects." This principle is fundamental to writing code that is easy to change and less prone to bugs.

1. What is the Single Responsibility Principle?

At its simplest, the Single Responsibility Principle (SRP) states that a class should have only one reason to change.

This means a class should have one, and only one, job or responsibility. If a class is responsible for multiple, unrelated tasks, a change request for one task might inadvertently break another.

Let's look at a concrete example to make this clear. Imagine a class that both manipulates text and prints it to the console.

Single Responsibility Principle in Java

This article from Baeldung provides a great introduction with a straightforward example. It will help us establish a baseline understanding of SRP.

Please read Section 2, 'Single Responsibility Principle'. Pay close attention to the TextManipulator class example. Notice how it initially mixes two responsibilities (text manipulation and printing) and how it's refactored into two separate classes, TextManipulator and TextPrinter.

As the article demonstrates, the TextManipulator class initially violates SRP by having a printText() method. Why is this a problem?

  • The responsibility of manipulating text (appending, replacing, deleting) is different from the responsibility of presenting that text.
  • The reason to change for text manipulation logic is different from the reason to change for printing logic. For example, you might want to change the printing logic to output to a file or a GUI instead of the console. Such a change should not require you to touch the TextManipulator class at all.

By separating the concerns into TextManipulator and TextPrinter, each class now has only one reason to change, adhering to SRP.

This visual diagram perfectly illustrates this kind of separation. A single, overloaded service is broken down into smaller, focused components.

Single Responsibility Principle (SRP) Illustration
This diagram shows a class that initially handles order processing, validation, database saving, and email notifications. To follow SRP, it's refactored into separate classes, each handling one distinct responsibility.

2. A Deeper Definition: Responsibility and "Actors"

The idea of "one reason to change" is powerful, but it can be a bit abstract. A more precise definition, popularized by Robert C. Martin ("Uncle Bob"), is:

A module should be responsible to one, and only one, actor.

An "actor" in this context isn't necessarily a person. It's a group of stakeholders or a business function that requires changes in the software. For example, the finance department is an actor, the human resources department is another, and the database administration team is a third.

When a single class serves multiple actors, you risk conflicts. A change requested by one actor can break functionality required by another.

This video provides an excellent explanation of this concept using a practical example.

Low Level Design 105 | Single Responsibility Principle in SOLID | 2022 | System Design

The simple definition is a good start, but the true power of SRP comes from thinking about 'actors'. This video explains this more advanced perspective beautifully.

Watch from the beginning to 05:17. The video will first debunk some common myths and then introduce the idea of an 'actor'. Pay close attention to the Employee class example. Notice how the needs of the CFO, HR, and Engineering (the 'actors') conflict and cause problems when their logic is combined in one class.

To summarize the video's key insight:
The Employee class had methods used by the CFO (calculateSalary), HR (calculateHours), and Engineering (saveEmployeeData). These are three different actors. When the calculateSalary method was changed at the request of the CFO, it unintentionally broke the calculateHours logic for HR because they shared an underlying private method.

This is a classic SRP violation. The solution is to separate the code that serves each actor into its own class:

  • SalaryCalculator (serves the CFO)
  • HoursCalculator (serves HR)
  • EmployeeRepository (serves Engineering/DBAs)

This way, changes for one actor are isolated and cannot break functionality for another.

3. SRP and High Cohesion

Following the Single Responsibility Principle leads to classes with high cohesion. Cohesion is a measure of how closely related the elements (methods and fields) of a class are.

  • High Cohesion (Good): A class does a well-defined job. All its methods and properties are related to that single purpose. Our refactored TextPrinter and SalaryCalculator are highly cohesive.
  • Low Cohesion (Bad): A class does many unrelated things. It's a "jack of all trades." Our original Employee class had low cohesion.

However, be careful not to take SRP to an extreme. The goal is not to have one method per class. That would lead to fragmented code and low cohesion, as you'd have many tiny classes that are useless on their own.

Single Responsibility Principle in Java

Let's revisit the Baeldung article to formally connect SRP with cohesion and to see a warning against misinterpreting the principle.

Please read Section 4, 'Cohesion', and Section 3, 'How Can This Principle Be Misleading?'. Focus on understanding how SRP is a tool to achieve high cohesion and the important warning about not over-decomposing your classes.

The key takeaway is to group methods that change for the same reasons and serve the same actor. The methods appendText, findWordAndReplace, and findWordAndDelete all serve the single purpose of "text manipulation," so they belong together in the TextManipulator class. Separating them would be a mistake.

4. SRP in Your Spring Boot Experience

As a Java Spring Boot developer, you have already been working with SRP, even if you didn't use the name. The Spring framework itself is heavily designed around this principle.

  • @Controller classes have one responsibility: handle incoming web requests, delegate to a service, and return a response. They don't contain business logic or database queries.
  • @Service classes have one responsibility: implement core business logic. They don't know about HTTP or SQL.
  • @Repository classes have one responsibility: handle data persistence (communicating with the database).

This separation is SRP in action at an architectural level.

Single Responsibility Principle in Java with Examples

This article from GeeksforGeeks highlights how frameworks you use every day, like Spring, are designed around SRP. This should connect the theory directly to your practical experience.

Read just the 'Examples' section. Notice how it points out that Spring Data JPA (Repositories), the Java Validation API, and the Spring Framework itself are all designed with SRP in mind. A JPA Repository, for instance, has the single responsibility of data persistence.

This connection shows that SRP isn't just an abstract academic concept; it's a practical tool used to build large, scalable applications like the ones you work on.

Test your understanding!

You are working on a Spring Boot e-commerce application. You have a class called ProductService with the following methods:

public class ProductService {
    // Fetches product details from the database
    public Product getProductDetails(Long productId) { /* ... */ }

    // Adds a product to the user's shopping cart
    public void addProductToCart(Long productId, int quantity) { /* ... */ }

    // Generates a PDF report of product inventory
    public byte[] generateInventoryReport() { /* ... */ }

    // Exports product data to a CSV file for backup
    public String exportProductsToCsv() { /* ... */ }
}

Identify the different responsibilities (or "actors") this class is serving. How would you refactor this class to better adhere to the Single Responsibility Principle?

Show answer

This ProductService class violates SRP by handling multiple, distinct responsibilities. We can identify at least three different "actors" or reasons for change:

  1. Core Business Logic: getProductDetails() and addProductToCart() relate to the core e-commerce functionality. The "actor" is the application user or the business logic domain itself. A change in business rules for products or carts would affect these methods.
  2. Reporting: generateInventoryReport() is a reporting feature. The actor is likely the inventory management or business analysis team. A change in the report format (e.g., adding new columns, changing the layout) would be a reason to modify this method.
  3. Data Management/Export: exportProductsToCsv() is a data export feature. The actor could be a database administrator or another system that consumes this data. A change in the CSV format or export logic would be a reason to change this method.

Refactoring Strategy:

To adhere to SRP, we should break this class down into more cohesive classes, each with a single responsibility:

  • ProductService: This class would retain the core business logic methods. The addProductToCart method could even be moved to a more specific ShoppingCartService.
    @Service
    public class ProductService {
        public Product getProductDetails(Long productId) { /* ... */ }
    }
    
  • ShoppingCartService: This class would handle all cart-related operations.
    @Service
    public class ShoppingCartService {
        public void addProductToCart(Long productId, int quantity) { /* ... */ }
    }
    
  • InventoryReportService: This class's sole purpose is to create reports.
    @Service
    public class InventoryReportService {
        public byte[] generatePdfReport() { /* ... */ }
    }
    
  • ProductExportService: This class is responsible for exporting data.
    @Service
    public class ProductExportService {
        public String exportToCsv() { /* ... */ }
    }
    

This refactoring makes the system far more maintainable. If the PDF report format changes, we only need to modify InventoryReportService, with no risk of breaking the core shopping cart logic or the CSV export functionality.

Conclusion

In this lesson, we dove into the Single Responsibility Principle, the "S" in SOLID. By ensuring our classes have only one reason to change, we create software that is more robust, easier to understand, and simpler to maintain.

Key Takeaways:

  • Core Definition: A class should have one, and only one, reason to change.
  • The "Actor" Perspective: A more precise way to think about this is that a class should be responsible to a single "actor" (a stakeholder or business function).
  • High Cohesion: Applying SRP is the primary way we achieve high cohesion in our classes, ensuring that all parts of a class work together towards a single purpose.
  • Practical Application: You are already using SRP when you separate concerns into @Controller, @Service, and @Repository layers in your Spring Boot applications.

In our next lesson, we'll move on to the Open/Closed Principle (OCP). Now that we know how to create small, cohesive classes (SRP), OCP will teach us how to structure them so that we can add new functionality without modifying existing, working code. This is a powerful technique for building flexible and stable systems.

Can't find a good explanation? Sign up and we'll make it for you

Sign up