OOPS Interview Questions · Question 18

What is the Single Responsibility Principle, and how can you identify a class with too many responsibilities?

Interview preparation resource from Gate Smashers.

Interview-ready answer

The Single Responsibility Principle (SRP) states that a class should have one responsibility: one cohesive purpose and one primary reason to change. A class has too many responsibilities when it combines unrelated concerns, such as business rules, persistence, notification, and formatting, so that changes in any of those areas require modifying the same class. Typical signs are low cohesion, methods and fields that serve unrelated purposes, dependencies on unrelated collaborators, a vague or overly broad class name, and change history showing that different kinds of changes repeatedly affect the class. Class size alone is not proof of an SRP violation; the key question is whether its members support the same responsibility and change together for the same reason.

SRP example — before and after (Java)java
/* Before: UserManager combines persistence and notification concerns. */
public class UserManager {
    private final Database db;
    private final EmailClient emailClient;

    public UserManager(Database db, EmailClient emailClient) {
        this.db = db;
        this.emailClient = emailClient;
    }

    public void createUser(User user) {
        db.insert("users", user.toMap());
        emailClient.send(user.getEmail(), "Welcome", "Thanks for signing up!");
    }

    public void deleteUser(String userId) {
        db.delete("users", userId);
        emailClient.sendAdminNotification("User deleted: " + userId);
    }
}

/* After: persistence and notification are separate responsibilities. */
public class UserRepository {
    private final Database db;

    public UserRepository(Database db) {
        this.db = db;
    }

    public void save(User user) {
        db.insert("users", user.toMap());
    }

    public void delete(String userId) {
        db.delete("users", userId);
    }
}

public class EmailService {
    private final EmailClient emailClient;

    public EmailService(EmailClient emailClient) {
        this.emailClient = emailClient;
    }

    public void sendWelcome(String to) {
        emailClient.send(to, "Welcome", "Thanks for signing up!");
    }

    public void notifyAdmin(String message) {
        emailClient.sendAdminNotification(message);
    }
}

/* This class coordinates the use case without implementing persistence or email details. */
public class UserManager {
    private final UserRepository userRepository;
    private final EmailService emailService;

    public UserManager(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }

    public void createUser(User user) {
        userRepository.save(user);
        emailService.sendWelcome(user.getEmail());
    }

    public void deleteUser(String userId) {
        userRepository.delete(userId);
        emailService.notifyAdmin("User deleted: " + userId);
    }
}
Understand it clearly

Meaning of SRP

SRP is one of the SOLID principles. It is commonly expressed as: a class should have one reason to change. More precisely, its methods and data should form one cohesive responsibility, often associated with a single kind of concern or stakeholder-driven change.

SRP does not mean every class must contain only one method or be small. A class can contain several related operations when they support the same abstraction and tend to change together.

How to identify too many responsibilities

Look at the class's behavior, dependencies, tests, and change history. The strongest evidence is that independent changes in different concerns require edits to the same class.

  • Mixed concerns: The class performs unrelated work, such as storing data, applying business rules, sending notifications, and formatting output.
  • Low cohesion: Its methods and fields naturally fall into separate groups, with little shared data or purpose.
  • Unrelated dependencies: It depends on collaborators from distinct concerns, such as a repository, mail client, and formatter, without one cohesive role explaining those dependencies.
  • Multiple reasons to change: Database changes, notification-policy changes, and presentation changes each require modifying the same class.
  • Broad naming: The class name is vague or does not accurately describe all of its behavior.
  • Difficult focused testing: Tests require many unrelated collaborators or mocks because the class coordinates several independent concerns.

Refactoring an SRP violation

First, identify groups of methods and data that change for different reasons. Extract those groups into focused classes, then let a higher-level coordinator compose them when an operation legitimately requires several responsibilities.

Refactor incrementally and preserve behavior with tests. Interfaces can be useful at boundaries where callers need to depend on an abstraction, but they are not required merely because a class is extracted.

  • Separate cohesive groups: Move persistence, notification, formatting, or other independent concerns into classes with clear, focused APIs.
  • Keep orchestration explicit: A coordinating class may call the focused components to complete a use case without taking ownership of their internal responsibilities.
  • Avoid over-splitting: Do not create separate classes for operations that are naturally part of the same cohesive abstraction.

Benefits and trade-offs

Applying SRP usually improves maintainability, readability, and testability because each class has a clearer purpose and smaller change surface. It can also reduce coupling between unrelated concerns.

However, splitting classes introduces more types and collaboration paths. Apply SRP to improve cohesion and isolate independent change, not simply to minimize the number of methods in each class.