Back to: Java Design Patterns
Single Responsibility Principle (SRP) in Java
In this article, I am going to discuss Single Responsibility Principle (SRP) in Java with Examples. Please read our previous article where we discussed the basic concepts of SOLID Design Principles in Java. The letter S in SOLID stands for the Single Responsibility Principle which is also known as SRP. The Single Responsibility Principle states that Each software module or class should have only one reason to change. In other words, we can say that each module or class should have only one responsibility to do. As part of this article, we are going to discuss the following pointers.
Single Responsibility Principle (SRP) in Java
The Single Responsibility Principle (SRP) is one of the five principles that make up the SOLID acronym. It states that a class should have only one reason to change. In other words, each class should be responsible for a single, well-defined functionality. By adhering to this principle, we ensure that our classes are focused, cohesive, and easier to maintain.
When a class becomes responsible for multiple tasks, it can become difficult to understand and maintain. Changes to one task may inadvertently affect other unrelated tasks. This can lead to bugs and make it harder to add new features or make changes to existing ones.
By keeping classes focused on a single responsibility, we can avoid these issues. Each class will have a clear purpose and will be easier to understand and modify. This makes our code more modular and flexible, allowing us to add new features or make changes with minimal impact on the rest of the system.
In practice, adhering to the Single Responsibility Principle often involves breaking down large classes into smaller ones, each with a well-defined responsibility. This can also improve code readability and make it easier for other developers to understand and work with the code.
What is Responsibility?
An application can have many functionalities (features). For example, if you are developing an e-commerce application, then that application may have many features or functionalities such as Registering users, providing login functionality, Displaying the product list, Allowing the user to place an order, Providing Payment Functionality, Shipping the Order, Billing the Order, Logging the Order Information for Auditing and for Security purpose, sending the Order Invoice to the customer, etc. You can consider these functionalities or features as responsibilities. And another point that you need to remember is, changing the functionality means you need to change the class that is responsible for that functionality.
Example to Understand Single Responsibility Principle (SRP) in Java
Let us say, we have a class called Order that represents an order in an e-commerce application. This class handles various responsibilities, violating the SRP. Here’s how the class might look:
public class Order { private List<Item> items; private Customer customer; public void addItem(Item item) { // logic to add an item to the order } public void removeItem(Item item) { // logic to remove an item from the order } public void calculateTotalPrice() { // logic to calculate the total price of the order } public void placeOrder() { // logic to place the order } public void sendConfirmationEmail() { // logic to send a confirmation email to the customer } }
In this example, the Order class has multiple responsibilities:
- Managing order items: The class is responsible for adding and removing items from the order.
- Calculating the total price: The class contains the logic to calculate the total price of the order.
- Placing the order: The class handles the logic to place the order.
- Sending confirmation emails: The class also has a method to send a confirmation email to the customer.
On the other hand, if SRP were to be implemented in the same example, it would look like this:
public class Order { private List<Item> items; private Customer customer; public void addItem(Item item) { // logic to add an item to the order } public void removeItem(Item item) { // logic to remove an item from the order } } public class OrderCalculator { public double calculateTotalPrice(Order order) { // logic to calculate the total price of the order } } public class OrderPlacer { public void placeOrder(Order order) { // logic to place the order } } public class EmailSender { public void sendConfirmationEmail(Customer customer) { // logic to send a confirmation email to the customer } }
In this refactored example, each class has a single responsibility:
- The Order class is responsible for managing the items in the order and handling basic order management operations.
- The OrderCalculator class is responsible for calculating the total price of an order. It takes an Order object as input and returns the calculated total price.
- The OrderPlacer class is responsible for placing the order. It takes an Order object as input and performs the necessary operations to place the order.
- The EmailSender class is responsible for sending confirmation emails to customers. It takes a Customer object as input and sends the email.
Overall, the Single Responsibility Principle is an important guideline for writing maintainable and robust code. By keeping classes focused on a single responsibility, we can create software that is easy to understand, maintain, and extend.
Advantages of the Single Responsibility Principle (SRP) in Java:
The followings are the advantages of using the Single Responsibility Principle in Java
- High Cohesion: By ensuring that each class has a single responsibility, the SRP promotes high cohesion. Cohesion refers to the degree to which the responsibilities of a class are related. High cohesion leads to more focused and understandable classes, making the code easier to read, maintain, and test.
- Improved Maintainability: With a single responsibility, classes become more modular and encapsulated. When a change is needed in the system, developers can easily identify the relevant class and make modifications without affecting other parts of the codebase. This reduces the risk of introducing unintended side effects and makes the system more maintainable over time.
- Code Reusability: SRP encourages the creation of small, reusable classes. Each class can be used in different contexts and scenarios, promoting code reuse and reducing duplication. This leads to more efficient development as developers can leverage existing classes rather than reinvent the wheel.
- Testability: Single-responsibility classes are typically easier to test. With a clear responsibility, it becomes simpler to define and write unit tests for each class, as they have well-defined inputs, outputs, and behavior. Isolating testing at the class level facilitates faster and more effective testing, improving overall software quality.
Disadvantages of the Single Responsibility Principle (SRP) in Java:
The followings are the disadvantages of using the Single Responsibility Principle in Java
- Increased Number of Classes: Following the SRP may lead to a higher number of classes in a codebase. If taken to an extreme, this can result in an overly granular design, making the system more complex and harder to comprehend. Striking the right balance between too many small classes and a few larger classes can be challenging.
- Increased Complexity of Interactions: When applying the SRP, classes become more specialized and focused. As a consequence, interactions between classes may become more complex, requiring careful design and coordination. Ensuring proper collaboration and communication between classes while maintaining loose coupling can be challenging, especially in large systems.
- Overhead of Indirection: Splitting responsibilities into separate classes may introduce additional layers of indirection. While this can provide flexibility and modularity, it can also increase the complexity of navigating through the codebase. Developers need to strike a balance between appropriate levels of abstraction and the risk of unnecessary indirection.
- Potential for Violations: It is not always easy to determine the right level of responsibility for a class. There is a risk of misinterpreting the principle and either creating classes that are too broad or classes that violate other principles, such as the Dependency Inversion Principle. It requires experience and careful judgment to correctly identify and assign responsibilities.
In the next article, I am going to discuss the Open-Closed Principle (OCP) in Java with Examples. Here, in this article, I try to explain Single Responsibility Principle (SRP) in Java with Examples. I hope you enjoy this Single Responsibility Principle (SRP) in the Java article.