โ† Back to OOP Concepts
1๏ธโƒฃ
Principles

Single Responsibility

A class should have only one reason to change โ€” it should do one thing and do it well.

The Problem

Classes that handle multiple responsibilities (e.g., business logic, persistence, and formatting all in one) become fragile: a tweak to one responsibility risks breaking another, and the class becomes a magnet for further unrelated changes.

How It Works

  • โ€บEach class or module encapsulates a single piece of functionality
  • โ€บResponsibilities are split into separate classes, each with a focused purpose
  • โ€บImproves testability โ€” smaller classes with fewer dependencies are easier to test in isolation
  • โ€บ"Reason to change" is the key heuristic, not "number of methods"

When to Use

โœ“A class mixes data access, business rules, and presentation logic
โœ“Refactoring "god classes" that have grown to do everything
โœ“Designing new classes โ€” ask "what is this class's one job?"

Real-World Examples

๐ŸŽ
iOS

Separating networking (APIClient), persistence (Storage), and presentation (ViewModel)

๐Ÿค–
Android

Splitting a fat Activity into ViewModel, Repository, and UI layers

๐ŸŒ
Web

Separating route handlers, business/service logic, and data-access layers

Code Examples

Swift
// Each type has exactly one responsibility
struct Invoice {
    let id: String
    let amount: Double
}

struct InvoiceCalculator {
    func total(for invoice: Invoice, taxRate: Double) -> Double {
        invoice.amount * (1 + taxRate)
    }
}

struct InvoicePrinter {
    func format(_ invoice: Invoice) -> String {
        "Invoice #\(invoice.id): $\(invoice.amount)"
    }
}

struct InvoiceRepository {
    func save(_ invoice: Invoice) {
        // persist to database
        print("Saved invoice \(invoice.id)")
    }
}