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)