Single Responsibility Principle (SRP)

Introduction

In this article, we will cover the Single Responsibility Principle (SRP).

Single Responsibility Principle (SRP)

  • "There should never be more than one reason for a class to change". It's tempting to jam-pack a class with a lot of functionality, like when you can only take one suitcase on your flight. The issue with this is that your class won't be conceptually cohesive and it will give it many reasons to change. Minimizing the amount of times you need to change a class is important.
  • It's important because if too much functionality is in one class and you modify a piece of it, it can be difficult to understand how that will affect other dependent modules in your codebase.

Let's take an example of a Banking System

A banking system allows customers to maintain a bank account where they can deposit and withdraw money. Additionally, the bank wants to provide a facility to print a statement of the account’s transaction history.

Violation of SRP/Bad Code

using System;
using System.Collections.Generic;

namespace DesignPattern
{
    public class BankAccount
    {
        public int AccountNumber { get; private set; }
        public double Balance { get; private set; }
        private List<string> Transactions = new List<string>();

        public BankAccount(int accountNumber)
        {
            AccountNumber = accountNumber;
        }

        public void Deposit(double amount)
        {
            Balance += amount;
            Transactions.Add($"Deposited ${amount}. New Balance: ${Balance}");
        }

        public void Withdraw(double amount)
        {
            Balance -= amount;
            Transactions.Add($"Withdrew ${amount}. New Balance: ${Balance}");
        }

        public void PrintStatement()
        {
            Console.WriteLine($"Statement for Account: {AccountNumber}");
            foreach (var transaction in Transactions)
            {
                Console.WriteLine(transaction);
            }
        }
    }
}

Note. Here, the BankAccount class handles

  • Transaction operations.
  • Printing the transaction statement.

Using SRP / Good Code

using System;
using System.Collections.Generic;

namespace DesignPattern
{
    public class BankAccount
    {
        public int AccountNumber { get; private set; }
        public double Balance { get; private set; }
        public List<string> Transactions = new List<string>();

        public BankAccount(int accountNumber)
        {
            AccountNumber = accountNumber;
        }

        public void Deposit(double amount)
        {
            Balance += amount;
            Transactions.Add($"Deposited ${amount}. New Balance: ${Balance}");
        }

        public void Withdraw(double amount)
        {
            Balance -= amount;
            Transactions.Add($"Withdrew ${amount}. New Balance: ${Balance}");
        }
    }

    public class StatementPrinter
    {
        public void Print(BankAccount account)
        {
            Console.WriteLine($"Statement for Account: {account.AccountNumber}");
            foreach (var transaction in account.Transactions)
            {
                Console.WriteLine(transaction);
            }
        }
    }
    
    //Testing the Single Responsibility Principle
    public class Program
    {
        public static void Main()
        {
            BankAccount vishalAccount = new BankAccount(123456);
            vishalAccount.Deposit(5000);
            vishalAccount.Withdraw(1000);

            StatementPrinter printer = new StatementPrinter();
            printer.Print(vishalAccount);
            
            Console.ReadKey();
        }
    }
}

SRP Output

Note. Here, following SRP

  • A cleaner approach would separate transaction management from statement printing:
  • BankAccount manages the transactions of the account.
  • StatementPrinter handles printing the transaction statement.


Similar Articles