Single Responsibility Principle Explained with Java Example
Understand the Single Responsibility Principle in Java with a practical example. Learn how it helps create clean, focused, and maintainable code.
Single Responsibility Principle (SRP)

The S in the SOLID principles stands for the Single Responsibility Principle. By the end of this chapter, you'll be able to answer the following:
-
What is the Single Responsibility Principle?
-
Why do we need it? In other words, what happens if we don’t follow it?
-
How do we apply it in real-world code?
What is the Single Responsibility Principle?
A class, module, or function should have only one reason to change. In simple terms, it should have only one responsibility.
This definition is quite self-explanatory. A class (or module or function) should focus on just one responsibility. When a piece of code takes care of multiple responsibilities, it can lead to several problems—which we’ll look at shortly.
But before that, there’s a common misconception I’ve often seen: people confuse responsibility with function. They think that a class with only one responsibility should also have only one function. This is not true.
A single responsibility can be implemented using multiple functions.
The key is that all those functions should work together to fulfill just one responsibility.
Why do we need it?
Let’s take a look at the code first.
In this example, the User class is doing way more than it should. It’s responsible for:
-
Saving to the database
-
Sending emails
-
Logging
-
And of course, handling user data
This clearly violates the Single Responsibility Principle, because the class has multiple reasons to change. For example:
-
If the database logic changes, you need to edit this class.
-
If the email provider changes, again, you need to edit this class.
-
Even if the logging strategy changes, you’re back editing the same class.
And that’s where problems begin.
What Problems Can This Cause?
-
Tight Coupling:
Ideally, our code should be loosely coupled. But here, everything is tightly tied together. Changing the email logic could accidentally break the database logic because they live in the same class.
-
Unnecessary Testing:
If you only change the logging logic, technically you should only test that. But because everything is tightly coupled, you might have to test the entire class including saving and email logic to be safe.
-
Merge Conflicts:
Suppose one developer is working on the database logic, and another is updating the email logic. Since both are modifying the same class, they’re more likely to run into version control conflicts.
-
Poor Reusability:
You can't reuse the email or logging logic in another class because it's buried inside the
Userclass. This makes your code less modular and harder to maintain.
These are just a few of the problems that can arise when we don't follow the Single Responsibility Principle. Next, we'll look at how to fix this by breaking responsibilities into smaller, focused classes.
How to Achieve the Single Responsibility Principle
We can achieve the Single Responsibility Principle (SRP) by breaking down responsibilities into smaller, focused classes each with one clear purpose.
Let’s look at the final, SRP-compliant version of the code:
Since we’ve separated responsibilities into their own classes, we avoid all the earlier problems:
-
UserRepository handles all DB operations.
-
LoggerService takes care of logging.
-
EmailService is focused only on sending emails.
-
UserService puts it all together — the business logic sits here.
Each class has one reason to change, and that’s exactly what SRP is all about.