DEV Community

ivan.gavlik
ivan.gavlik

Posted on • Updated on

Single responsibility principle explained + example in Java

The Single Responsibility Principle (SRP) is one of the SOLID principles of software design that states a class should have only one responsibility or reason to change. In Java, SRP can be implemented in multiple ways. Here are some of them:

  • Separate classes for each responsibility: You can create separate classes for each responsibility, such as input handling, data processing, and output rendering. This way, each class will have only one responsibility.
  • Use interfaces: You can define interfaces for each responsibility and implement them separately. This way, each class will have only one responsibility, and you can easily swap the implementations without affecting the rest of the code.
  • Abstract classes: You can use abstract classes to define common behavior, and then create concrete classes that implement specific responsibilities. This way, you can ensure each class has only one responsibility.

It is up to the developer to choose the best approach based on the specific requirements and constraints of the project.

SRP can be applied at bigger scale then is it called Separation of concerns: separate code into modules, each responsible for a specific functionality. This way, each module will have only one responsibility.

Example: SRP in Java using separate classes for each responsibility

Problem description:

Java application that reads numerical data from a file, finds average value and then outputs the results.

Solution

  1. Create a separate class for input handling:

    public class InputHandler {
        public static List<Double> readData(String filename){
            // Code to read data from file
        }
    }
    

    This class is responsible for handling the input data and reads it from the file. It has only one responsibility, which is to read data from a file.
    resources

  2. Create a separate class for data processing:

    public class DataProcessor {
        public static double calculateAverage(List<Double> data) {
            // Code to perform calculations on data
        }
    }
    

    This class is responsible for processing the input data and calculates the average value. It has only one responsibility, which is to perform calculations on the input data.

  3. Create a separate class for output rendering:

    public class OutputRenderer {
        public static void displayResults(double result) {
            // Code to render output
        }
    }
    

    This class is responsible for rendering the output and displays the results. It has only one responsibility, which is to render the output in a user-friendly way.

  4. Finally, create a main class to tie everything together:

    public class Main {
        public static void main(String[] args) {
            String filename = input.txt;
            List<Double> data = InputHandler.readData(filename);
            double result = DataProcessor.calculateAverage(data);
            OutputRenderer.displayResults(result);
        }
    }
    

    This main class simply calls the methods from the input handling, data processing, and output rendering classes in sequence to read the input data, process it, and display the results.

We are going to test this implementation for future changes.

First request for change:

Client ask you to read data from two files,
Solution: You only need to change InpuntHandler and test only it, so your scope of the change is smaller and easier to test.

Second request for change:

The first line is the file is a title for the output, so you need to display output in the format

Solution: Create new class for holding data and title.

public class DataHolder {
    private String title;
    private List<Double> data;
    private Double average:
}
Enter fullscreen mode Exit fullscreen mode

You need to change InpuntHandler, DataProcessor, OutputRenderer but still the reason for change in each class is only one because each class has only one responsibility:

  • InpuntHandler is reading file and populating DataHolder class
  • DataProcessor calculation is the same, only parameter is changed.
  • OutputRenderer change the output to match the format

Main class for the solution:

public class Main {
    public static void main(String[] args) {
        String filename = input.txt;
        DataHolder data = InputHandler.readData(filename);
        data = DataProcessor.calculateAverage(data);
        OutputRenderer.displayResults(data);
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

By separating the responsibilities into different classes, you’ve ensured that each class has only one responsibility, which makes the code easier to maintain, test, and extend.

Single responsibility principle is guide, helping you choose between paths, is should be floating your conscious thought, when coding alwas ask yourself does method/class/interface/abstract class/package have only one responsibility or only one reason to change.

Top comments (0)