#1 Single Responsibility Principle ['S' in SOLID]
Tags: singleresponsibility, solidprinciples, designprinciples
Published: 2024-06-29 12:14:05

**SRP - Single Responsibility Principle**
The Single Responsibility Principle is the first principle in the Solid Design Principles.
1. A class should have only one reason to change.
2. Each class should focus on a single job or responsibility.

**Violating SRP:**

```swift
class BankAccount {
    var accountNumber: String
    var balance: Double
    
    init(accountNumber: String, balance: Double) {
        self.accountNumber = accountNumber
        self.balance = balance
    }
    
    func deposit(amount: Double) {
        balance += amount
        print("Deposited \(amount). New balance is \(balance)")
    }
    
    func withDraw(amount: Double) {
        if (balance >= amount) {
            balance -= amount
            print("Withdrew \(amount). New balance is \(balance)")
        } else {
            print("Handling the insufficient balance.")
        }
    }
    
    func printStatement() {
        print("Account Statement for \(accountNumber): Balance is \(balance)")
    }
    
    func notifyUser() {
        print("Notifying user of transaction for account \(accountNumber)")
    }
}

// Usage
print("Before Applying SRP:")
let bankAccount = BankAccount(accountNumber: "BANK123", balance: 1000)
bankAccount.deposit(amount: 100)
bankAccount.withDraw(amount: 500)
bankAccount.withDraw(amount: 3000)
bankAccount.printStatement()
bankAccount.notifyUser()
```

**Adhering to SRP**
To adhere to SRP, separate the responsibilities into different classes:

```swift
class BankAccountWithSRP {
    var accountNumber: String
    var balance: Double
    
    init(accountNumber: String, balance: Double) {
        self.accountNumber = accountNumber
        self.balance = balance
    }
    
    func deposit(amount: Double) {
        balance += amount
        print("Deposited \(amount). New balance is \(balance)")
    }
    
    func withDraw(amount: Double) {
        if (balance >= amount) {
            balance -= amount
            print("Withdrew \(amount). New balance is \(balance)")
        } else {
            print("Handling the insufficient balance.")
        }
    }
}

class StatementPrinter {
    func printStatement(for account: BankAccountWithSRP) {
        print("Account Statement for \(account.accountNumber): Balance is \(account.balance)")
    }
}

class NotificationService {
    func notifyUser(for account: BankAccountWithSRP) {
        print("Notifying user of transaction for account \(account.accountNumber)")
    }
}

// Usage
print("\n\nAfter Applying SRP:")
let bankAccountSRP = BankAccountWithSRP(accountNumber: "BANK123", balance: 1000)
bankAccountSRP.deposit(amount: 500)
bankAccountSRP.withDraw(amount: 700)
bankAccountSRP.withDraw(amount: 3000)

let statementPrinter = StatementPrinter()
let notificationService = NotificationService()

statementPrinter.printStatement(for: bankAccountSRP)
notificationService.notifyUser(for: bankAccountSRP)
```

**Benefits of Adhering to SRP:**
1. Improved Readability:
   * Each class has a clear and focused responsibility, making the code easier to understand.

2. Enhanced Maintainability:
   * Changes to statement printing or notification logic do not affect the BankAccount class.

3. Increased Reusability:
   * The StatementPrinter and NotificationService classes can be reused independently in other application parts.

4. Simplified Testing:
   * Each class can be tested independently, making unit testing more straightforward.

**Drawbacks:**
1. More Classes:
   * Can lead to many small classes.
2. Complex Dependency Management:
   * More dependencies to manage.
3. Design and Refactoring Overhead:
   * Requires more effort to design and refactor.
4. Risk of Over-Engineering:
   * Can make simple problems overly complex.
5. Performance Considerations:
   * More object creation and method calls.

**Mitigating Drawbacks:**
1. Balanced Approach:
   * Apply SRP judiciously.
2. Effective Documentation:
   * Clear Documentation helps navigate the codebase.
3. Use Patterns and Frameworks:
   * Design patterns and dependency management tools can help.
4. Team Alignment:
   * Ensure the team has a shared understanding of SRP.
5. Performance Profiling:
   * Profile and optimize performance as needed.

**Conclusion:**
By understanding and applying the Single Responsibility Principle thoughtfully, you can create more maintainable, understandable, and flexible software.

[Open/Close Principle](https://dev.to/vinaykumar0339/2-open-close-principle-o-in-solid-2jj6)
[Check My GitHub Swift Playground Repo.](https://github.com/vinaykumar0339/SolidDesignPrinciples)