Single Responsibility Principle in Java with Example

Introduction

The Single Responsibility Principle (SRP) is one of the five SOLID principles of object-oriented design. SRP states that a class should have only one reason to change, meaning it should have only one responsibility or job. This principle helps in creating more maintainable and understandable code by ensuring that each class addresses only one concern.

Table of Contents

  1. What is the Single Responsibility Principle?
  2. Benefits of the Single Responsibility Principle
  3. Example: Violation of SRP
  4. Example: Adherence to SRP
  5. Real-World Example
  6. Conclusion

1. What is the Single Responsibility Principle?

The Single Responsibility Principle (SRP) asserts that a class should only have one reason to change, implying it should have only one responsibility or purpose. This principle helps in building classes that are easier to understand, test, and maintain by ensuring each class is focused on a single aspect of the application.

2. Benefits of the Single Responsibility Principle

  • Improved Maintainability: Changes to a single responsibility affect only one class, making the codebase easier to maintain.
  • Enhanced Readability: Classes with a single responsibility are easier to read and understand.
  • Increased Reusability: Classes focused on a single responsibility can be reused in different contexts without modification.
  • Simplified Testing: Testing is more straightforward for classes with a single responsibility.

3. Example: Violation of SRP

In this example, a User class is responsible for both user management and email sending, violating SRP.

public class User {
    private String name;
    private String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public void saveUser() {
        // Code to save user to database
        System.out.println("User saved to database.");
    }

    public void sendEmail(String message) {
        // Code to send email
        System.out.println("Email sent to " + email + " with message: " + message);
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }
}

public class Main {
    public static void main(String[] args) {
        User user = new User("John Doe", "[email protected]");
        user.saveUser();
        user.sendEmail("Welcome to our platform!");
    }
}

Issues:

  • The User class is responsible for both saving the user and sending emails.
  • Any change in email sending logic will require changes in the User class, violating SRP.

4. Example: Adherence to SRP

By splitting responsibilities into separate classes, we adhere to SRP.

Step 1: Define the User Class

public class User {
    private String name;
    private String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }
}

Step 2: Define the UserRepository Class

public class UserRepository {
    public void saveUser(User user) {
        // Code to save user to database
        System.out.println("User " + user.getName() + " saved to database.");
    }
}

Step 3: Define the EmailService Class

public class EmailService {
    public void sendEmail(User user, String message) {
        // Code to send email
        System.out.println("Email sent to " + user.getEmail() + " with message: " + message);
    }
}

Step 4: Main Class to Demonstrate SRP

public class Main {
    public static void main(String[] args) {
        User user = new User("John Doe", "[email protected]");

        UserRepository userRepository = new UserRepository();
        userRepository.saveUser(user);

        EmailService emailService = new EmailService();
        emailService.sendEmail(user, "Welcome to our platform!");
    }
}

Explanation:

  • User: Class only responsible for storing user details.
  • UserRepository: Class responsible for saving the user to the database.
  • EmailService: Class responsible for sending emails to users.
  • Main: Class demonstrating the use of SRP by separating concerns into different classes.

5. Real-World Example

Example: Library System

In a library management system, consider separating the responsibilities of book management, member management, and loan management into different classes.

Book Class

public class Book {
    private String title;
    private String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }
}

Member Class

public class Member {
    private String name;
    private String memberId;

    public Member(String name, String memberId) {
        this.name = name;
        this.memberId = memberId;
    }

    public String getName() {
        return name;
    }

    public String getMemberId() {
        return memberId;
    }
}

LoanService Class

public class LoanService {
    public void loanBook(Member member, Book book) {
        // Code to loan book to member
        System.out.println("Book '" + book.getTitle() + "' loaned to member " + member.getName() + ".");
    }
}

Explanation:

  • Book: Class responsible for storing book details.
  • Member: Class responsible for storing member details.
  • LoanService: Class responsible for managing book loans.
  • Main: Class demonstrating the use of SRP by separating concerns into different classes.

Conclusion

The Single Responsibility Principle (SRP) is a fundamental concept in object-oriented design that promotes high cohesion and low coupling by ensuring that each class has only one responsibility or reason to change. By adhering to SRP, developers can create more maintainable, understandable, and flexible code. This principle is critical for building robust and scalable applications.

Happy coding!

Comments

  1. Wow ! ..Beautifully explained with Real word examples.

    ReplyDelete
  2. I've got an simple example below please have a look at the generateId() method and let me know is it being violate the SRP?

    public String generateId() {
    String ramdomValue = UUID.randomUUID().toString();
    String prefixValue = getPrefixFromConfig();
    return String.format("%s-%s", prefixValue, ramdomValue)
    }

    private String getPrefixFromConfig() {
    //get prefix value set from configuration file
    }

    If we try to refactor/decoupling code then our code will be more fit to the SRP, is it correct? Please advice!

    ReplyDelete

Post a Comment

Leave Comment