SRP - Single Responsibility Principle
The Single Responsibility Principle is the first principle in the Solid Design Principles.
- A class should have only one reason to change.
- Each class should focus on a single job or responsibility.
Violating SRP:
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:
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:
-
Improved Readability:
- Each class has a clear and focused responsibility, making the code easier to understand.
-
Enhanced Maintainability:
- Changes to statement printing or notification logic do not affect the BankAccount class.
-
Increased Reusability:
- The StatementPrinter and NotificationService classes can be reused independently in other application parts.
-
Simplified Testing:
- Each class can be tested independently, making unit testing more straightforward.
Drawbacks:
- More Classes:
- Can lead to many small classes.
- Complex Dependency Management:
- More dependencies to manage.
- Design and Refactoring Overhead:
- Requires more effort to design and refactor.
- Risk of Over-Engineering:
- Can make simple problems overly complex.
- Performance Considerations:
- More object creation and method calls.
Mitigating Drawbacks:
- Balanced Approach:
- Apply SRP judiciously.
- Effective Documentation:
- Clear Documentation helps navigate the codebase.
- Use Patterns and Frameworks:
- Design patterns and dependency management tools can help.
- Team Alignment:
- Ensure the team has a shared understanding of SRP.
- 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.
Top comments (0)