DEV Community

vinaykumar0339
vinaykumar0339

Posted on • Edited on

#1 Single Responsibility Principle ['S' in SOLID]

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:

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()
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Check My GitHub Swift Playground Repo.

Image of Datadog

How to Diagram Your Cloud Architecture

Cloud architecture diagrams provide critical visibility into the resources in your environment and how they’re connected. In our latest eBook, AWS Solution Architects Jason Mimick and James Wenzel walk through best practices on how to build effective and professional diagrams.

Download the Free eBook

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up