Skip to content
Part IA Michaelmas Term

Single Responsibility Principle

The Principle

The Single Responsibility Principle (SRP) states:

A class should have one, and only one, reason to change.

Formulated by Robert C. Martin (Uncle Bob), this principle captures the idea that a class should be responsible to one — and only one — stakeholder or concern. If a class serves multiple masters, changes demanded by one will risk breaking functionality that the other depends on.

A “reason to change” corresponds to a distinct axis of change in the system. If the format of input data changes, the class that parses that data must change. If the database schema changes, the persistence class must change. These are separate reasons — they should live in separate classes.

An SRP Violation

Consider a class that mixes three unrelated responsibilities:

public class EmployeeReport {
    public List<Employee> loadFromFile(String path) {
        // parse CSV, handle I/O errors, build Employee objects
    }

    public double calculateAverageSalary() {
        // iterate over employees, compute statistics
    }

    public String renderAsHTML() {
        // generate HTML markup with inline styles
    }
}

This class has at least three reasons to change:

  1. The file format changes (CSV to JSON, or new columns added) — loadFromFile must change
  2. The calculation logic changes (median instead of mean, exclude part-timers) — calculateAverageSalary must change
  3. The presentation format changes (HTML to PDF, or a new CSS framework) — renderAsHTML must change

Each of these changes could be requested independently. When they live in the same class, a change to the file format carries the risk of accidentally breaking the HTML rendering. A developer making a presentation change must read and understand the file-parsing code to avoid side effects. This is unnecessary cognitive load.

Applying SRP: The Split

Separate into three classes, each with one reason to change:

public class EmployeeLoader {
    public List<Employee> loadFromFile(String path) { ... }
}

public class SalaryCalculator {
    public double calculateAverageSalary(List<Employee> employees) { ... }
}

public class ReportRenderer {
    public String renderAsHTML(List<Employee> employees, double avgSalary) { ... }
}

Now:

  • A file-format change touches only EmployeeLoader
  • A calculation change touches only SalaryCalculator
  • A presentation change touches only ReportRenderer

Each class is smaller, simpler, and can be tested in isolation.

Model-View-Controller (MVC)

MVC is an architectural pattern that applies SRP at the system level, separating an interactive application into three kinds of component:

ComponentResponsibilityReason to Change
ModelBusiness logic, data, rulesBusiness requirements change
ViewPresentation, rendering, layoutLook and feel changes
ControllerUser input handling, coordinationInput mechanisms change (keyboard → touch)
User input ──→ Controller ──→ Model (update state)
                  ↑               │
                  │               ↓
                  └──── View ←────┘ (observe state)

Each component has a single responsibility. The model does not know how it is displayed. The view does not know how data is computed. The controller does not know how rendering works. This separation makes each part independently modifiable and testable.

Benefits of SRP

Easier to Understand

A class with one responsibility is small and focused. Its name describes its purpose. A developer can read it without needing to mentally filter out unrelated code.

Easier to Test

@Test
public void testAverageSalary() {
    SalaryCalculator calc = new SalaryCalculator();
    List<Employee> testData = List.of(
        new Employee("Alice", 50000),
        new Employee("Bob", 60000)
    );
    assertEquals(55000.0, calc.calculateAverageSalary(testData), 0.001);
}

Testing SalaryCalculator requires only employee data — no filesystem, no HTML templating. The test is fast, deterministic, and easy to write.

Easier to Reuse

SalaryCalculator can be used in a command-line tool, a web service, and a batch report, without dragging in dependencies on file I/O or HTML libraries.

Easier to Modify

When a class has one responsibility, the scope of any change is clear and bounded. You know exactly which class to modify and what the blast radius will be.

SRP vs God Class

SRP is the principle that directly opposes the God class anti-pattern. A God class is a class with many responsibilities; SRP says a class should have exactly one. The God class is what you get when SRP is ignored.

SRP and Cohesion

SRP and cohesion are closely related but distinct. SRP is about external reasons for change — who might ask for modifications? Cohesion is about internal relatedness — do the class’s members work together toward a single purpose?

A class can have high cohesion (all methods operate on the same data) but still violate SRP (the data represents multiple unrelated concepts that could change for different reasons). In practice, high cohesion correlates with SRP compliance, but the two concepts are conceptually different. The Tripos may ask you to distinguish them.

How Many Responsibilities Does a Class Have?

A practical test: describe the class’s purpose in one sentence. If the sentence contains the word “and” (describing unrelated activities), the class likely has multiple responsibilities.

  • “This class loads employees from a CSV file and calculates salary statistics and renders HTML reports.” — three responsibilities.
  • “This class loads employees from a file.” — one responsibility.

Another test: list the stakeholders who might request changes to the class. If multiple distinct groups (the DBA team, the UX team, the business analysts) have a stake in the same class, it has multiple responsibilities.